user message limits
by LC Bruzenak
I know I can go look at the code, however I figured I'd ask here first
about the limits on the user message in both audit_log_user_message and
ausearch.
With audit_log_user_message the maximum length allowed appears to be
around MAX_AUDIT_MESSAGE_LENGTH-100. I think it may depend on the
executable name length (and other stuff auto-pushed into the string)
which is why I say "around".
Even when I get a successful return value (from audit_log_user_message),
I don't get my string back out in "ausearch" unless it is WAY smaller -
~1K or less I think.
Any ideas/thoughts?
This is the latest (1.7.11-2) audit package.
Thx,
LCB.
--
LC (Lenny) Bruzenak
lenny(a)magitekltd.com
11 years, 3 months
AUDIT_SIGNAL_INFO
by Matthew Booth
Under what circumstances will the RHEL 4 kernel generate a message of
type AUDIT_SIGNAL_INFO? My understanding is that it should be sent when
a process sends a signal to the audit daemon, however I have not
observed that. Any ideas?
Thanks,
Matt
--
Matthew Booth, RHCA, RHCSS
Red Hat, Global Professional Services
M: +44 (0)7977 267231
GPG ID: D33C3490
GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
12 years, 6 months
Near Term Audit Road Map
by Steve Grubb
Hi,
With the proposals sent to the list, I wanted to talk about how this might
play out code-wise. With regard to the current code base, I am working on a
1.8 release. This would represent finishing the remote logging app and
nothing more. The 1.8 series would become just an update series just like the
1.0.x series did.
In parallel with finishing remote logging, I would release a 2.0 version.
Patches applied to 1.8 would also be applied to 2.0. A 2.1 release would
signify the completion of remote logging that branch. I would recommend this
branch for all distributions pulling new code in.
The 2.0 branch will also have a couple more changes. I want to split up the
audit source code a little bit. I want to drop the system-config-audit code
and let it become standalone package updated and distributed separately.
I also want to drop all audispd-plugins in the 2.0 branch and have them
released separately. They cause unnecessary build dependencies for the audit
package.
During the work for a 2.2 release, I would also like to pull the audispd
program inside auditd. In the past, I tried to keep auditd lean and single
purpose, but with adding remote logging and kerberos support, we already have
something that is hard to analyze. So, to improve performance and decrease
system load, the audit daemon will also do event dispatching.
Would this proposal impact anyone in a Bad Way?
Thanks,
-Steve
12 years, 6 months
[PATCH] Add auditd listener and remote audit protocol
by DJ Delorie
Second in a series, a bit bigger than the first one.
(http://www.redhat.com/archives/linux-audit/2008-August/msg00070.html)
The goal of this patch is to add the server side of the remote logging
feature. To this end, a new auditd-listener.c is added which listens
on a TCP port for connections from other systems' audisp-remote
plugins. A new (private) protocol is added which prepends each
message with a header, giving length, status, version, and sequence
information. Each message begets a reply from the server, so we can
pass along status like "disk full" or "ok". Currently, these call a
set of stub functions, as the details of performing appropriate
actions from the plugin are yet to be decided.
The remote plugin has a new option "format" for "ascii" or "managed"
to choose between the old protocol (ascii strings) and the new one
(the header with ACK, default).
The listener will accept either format. It has new options for the
listen port, accept queue size, and acceptable client-side ports.
Comments?
DJ
Proposed ChangeLog entry:
- Add TCP listener and managed remote protocol features.
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/audisp-remote.c trunk/audisp/plugins/remote/audisp-remote.c
--- pristine/audisp/plugins/remote/audisp-remote.c 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/audisp-remote.c 2008-08-14 14:10:48.000000000 -0400
@@ -30,7 +30,11 @@
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#include "libaudit.h"
+#include "private.h"
#include "remote-config.h"
#define CONFIG_FILE "/etc/audisp/audisp-remote.conf"
@@ -68,6 +72,56 @@
hup = 0;
}
+/*
+ * Handlers for various events coming back from the remote server.
+ * Return -1 if the remote dispatcher should exit.
+ */
+
+/* Loss of sync - got an invalid response. */
+static int sync_error_handler (const char *why)
+{
+ /* "why" has human-readable details on why we've lost (or will
+ be losing) sync. */
+ syslog (LOG_ERR, "lost/losing sync, %s", why);
+ return -1;
+}
+
+static int remote_disk_low_handler (const char *message)
+{
+ syslog (LOG_WARNING, "remote disk low, %s", message);
+ return 0;
+}
+
+static int remote_disk_full_handler (const char *message)
+{
+ syslog (LOG_ERR, "remote disk full, %s", message);
+ return -1;
+}
+
+static int remote_disk_error_handler (const char *message)
+{
+ syslog (LOG_ERR, "remote disk error, %s", message);
+ return -1;
+}
+
+static int remote_server_ending_handler (const char *message)
+{
+ syslog (LOG_INFO, "remote server ending, %s", message);
+ return -1;
+}
+
+static int generic_remote_error_handler (const char *message)
+{
+ stop = 1;
+ syslog(LOG_INFO, "audisp-remote: remote error: %s", message);
+ return -1;
+}
+static int generic_remote_warning_handler (const char *message)
+{
+ syslog(LOG_INFO, "audisp-remote: remote warning: %s", message);
+ return 0;
+}
+
int main(int argc, char *argv[])
{
@@ -122,6 +176,7 @@
struct addrinfo *ai;
struct addrinfo hints;
char remote[BUF_SIZE];
+ int one=1;
memset(&hints, '\0', sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV;
@@ -140,12 +195,35 @@
freeaddrinfo(ai);
return -1;
}
+
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+
+ if (config.local_port != 0) {
+ struct sockaddr_in address;
+
+ memset (&address, 0, sizeof(address));
+ address.sin_family = htons(AF_INET);
+ address.sin_port = htons(config.local_port);
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if ( bind ( sock, (struct sockaddr *)&address, sizeof(address)) ) {
+ syslog(LOG_ERR, "Cannot bind local socket to port %d - exiting",
+ config.local_port);
+ close(sock);
+ return -1;
+ }
+
+ }
if (connect(sock, ai->ai_addr, ai->ai_addrlen)) {
syslog(LOG_ERR, "Error connecting to %s: %s - exiting",
config.remote_server, strerror(errno));
freeaddrinfo(ai);
return -1;
}
+
+ setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (int));
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int));
+
freeaddrinfo(ai);
return 0;
}
@@ -166,16 +244,143 @@
return rc;
}
-static int relay_sock(const char *s, size_t len)
+static int ar_write (int sock, const void *buf, int len)
{
int rc;
-
do {
- rc = write(sock, s, len);
+ rc = write(sock, buf, len);
} while (rc < 0 && errno == EINTR);
- if (rc > 0)
- return 0;
- return -1;
+ return rc;
+}
+
+static int ar_read (int sock, void *buf, int len)
+{
+ unsigned char *obuf = buf;
+ int rc = 0, r;
+ while (len > 0) {
+ do {
+ r = read(sock, buf, len);
+ } while (r < 0 && errno == EINTR);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+ rc += r;
+ buf = (void *)((char *)buf + r);
+ len -= r;
+ }
+ return rc;
+}
+
+static int relay_sock_ascii(const char *s, size_t len)
+{
+ int rc;
+
+ rc = ar_write(sock, s, len);
+ if (rc <= 0) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int relay_sock_managed(const char *s, size_t len)
+{
+ static int sequence_id = 1;
+ int rc;
+ unsigned char header[AUDIT_RMW_HEADER_SIZE];
+ int hver, mver;
+ uint32_t magic, type, rlen, seq;
+ char msg[MAX_AUDIT_MESSAGE_LENGTH+1];
+
+ sequence_id ++;
+ AUDIT_RMW_PACK_HEADER (header, 0, 0, len, sequence_id);
+ rc = ar_write(sock, header, AUDIT_RMW_HEADER_SIZE);
+ if (rc <= 0) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+ rc = ar_write(sock, s, len);
+ if (rc <= 0) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+ rc = ar_read (sock, header, AUDIT_RMW_HEADER_SIZE);
+ if (rc < 16) {
+ stop = 1;
+ syslog(LOG_ERR, "connection to %s closed unexpectedly - exiting",
+ config.remote_server);
+ return -1;
+ }
+
+
+ if (! AUDIT_RMW_IS_MAGIC (header, AUDIT_RMW_HEADER_SIZE))
+ /* FIXME: the right thing to do here is close the socket and start a new one. */
+ return sync_error_handler ("bad magic number");
+
+ AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, rlen, seq);
+
+ if (rlen > MAX_AUDIT_MESSAGE_LENGTH)
+ return sync_error_handler ("message too long");
+
+ if (rlen > 0
+ && ar_read (sock, msg, rlen) < rlen)
+ return sync_error_handler ("ran out of data reading reply");
+ msg[rlen] = 0;
+
+ if (seq != sequence_id)
+ /* FIXME: should we read another header and
+ see if it matches? If so, we need to deal
+ with timeouts. */
+ return sync_error_handler ("mismatched response");
+
+ /* Specific errors we know how to deal with. */
+
+ if (type == AUDIT_RMW_TYPE_ENDING)
+ return remote_server_ending_handler (msg);
+ if (type == AUDIT_RMW_TYPE_DISKLOW)
+ return remote_disk_low_handler (msg);
+ if (type == AUDIT_RMW_TYPE_DISKFULL)
+ return remote_disk_full_handler (msg);
+ if (type == AUDIT_RMW_TYPE_DISKERROR)
+ return remote_disk_error_handler (msg);
+
+ /* Generic errors. */
+ if (type & AUDIT_RMW_TYPE_FATALMASK)
+ return generic_remote_error_handler (msg);
+ if (type & AUDIT_RMW_TYPE_WARNMASK)
+ return generic_remote_warning_handler (msg);
+
+ return 0;
+}
+
+static int relay_sock(const char *s, size_t len)
+{
+ int rc;
+
+ switch (config.format)
+ {
+ case F_MANAGED:
+ rc = relay_sock_managed (s, len);
+ break;
+ case F_ASCII:
+ rc = relay_sock_ascii (s, len);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ return rc;
}
static int relay_event(const char *s, size_t len)
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/audisp-remote.conf trunk/audisp/plugins/remote/audisp-remote.conf
--- pristine/audisp/plugins/remote/audisp-remote.conf 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/audisp-remote.conf 2008-08-14 15:11:23.000000000 -0400
@@ -5,8 +5,9 @@
remote_server =
port = 60
+#local_port =
transport = tcp
mode = immediate
queue_depth = 20
fail_action = SYSLOG
-
+format = managed
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/audisp-remote.conf.5 trunk/audisp/plugins/remote/audisp-remote.conf.5
--- pristine/audisp/plugins/remote/audisp-remote.conf.5 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/audisp-remote.conf.5 2008-08-14 15:36:53.000000000 -0400
@@ -11,6 +11,13 @@
.I port
This option is an unsigned integer that indicates what port to connect to on the remote machine.
.TP
+.I local_port
+This option is an unsigned integer that indicates what local port to
+connect from on the local machine. If unspecified (the default) or
+set to the word
+.I any
+then any available unpriviledged port is used.
+.TP
.I transport
This parameter tells the remote logging app how to send events to the remote system. Valid values are
.IR tcp ", and " ssl ".
@@ -55,7 +62,22 @@
option will cause the remote logging app to put the computer system in single user mode.
.I halt
option will cause the remote logging app to shutdown the computer system.
+.TP
+.I format
+This parameter tells the remote logging app what data format will be
+used for the messages sent over the network. The default is
+.I managed
+which adds some overhead to ensure each message is properly handled on
+the remote end, and to receive status messages from the remote server.
+If
+.I ascii
+is given instead, each message is a simple ASCII text line with no
+overhead at all.
+.SH "NOTES"
+Specifying a local port may make it difficult to restart the audit
+subsystem due to the previous connection being in a TIME_WAIT state,
+if you're reconnecting to and from the same hosts and ports as before.
.SH "SEE ALSO"
.BR audispd (8),
.BR audisp-remote(8).
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/remote-config.c trunk/audisp/plugins/remote/remote-config.c
--- pristine/audisp/plugins/remote/remote-config.c 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/remote-config.c 2008-08-13 22:19:31.000000000 -0400
@@ -62,6 +62,8 @@
remote_conf_t *config);
static int port_parser(struct nv_pair *nv, int line,
remote_conf_t *config);
+static int local_port_parser(struct nv_pair *nv, int line,
+ remote_conf_t *config);
static int transport_parser(struct nv_pair *nv, int line,
remote_conf_t *config);
static int mode_parser(struct nv_pair *nv, int line,
@@ -70,16 +72,20 @@
remote_conf_t *config);
static int fail_action_parser(struct nv_pair *nv, int line,
remote_conf_t *config);
+static int format_parser(struct nv_pair *nv, int line,
+ remote_conf_t *config);
static int sanity_check(remote_conf_t *config, const char *file);
static const struct kw_pair keywords[] =
{
{"remote_server", server_parser, 0 },
{"port", port_parser, 0 },
+ {"local_port", local_port_parser, 0 },
{"transport", transport_parser, 0 },
{"mode", mode_parser, 0 },
{"queue_depth", depth_parser, 0 },
{"fail_action", fail_action_parser, 0 },
+ {"format", format_parser, 0 },
{ NULL, NULL }
};
@@ -107,6 +113,13 @@
{ NULL, 0 }
};
+static const struct nv_list format_words[] =
+{
+ {"ascii", F_ASCII },
+ {"managed", F_MANAGED },
+ { NULL, 0 }
+};
+
/*
* Set everything to its default value
*/
@@ -114,11 +127,13 @@
{
config->remote_server = NULL;
config->port = 60;
+ config->local_port = 0;
config->port = T_TCP;
config->mode = M_IMMEDIATE;
config->queue_depth = 20;
config->fail_action = F_SYSLOG;
config->fail_exe = NULL;
+ config->format = F_MANAGED;
}
int load_config(remote_conf_t *config, const char *file)
@@ -392,6 +407,46 @@
return 0;
}
+static int local_port_parser(struct nv_pair *nv, int line, remote_conf_t *config)
+{
+ const char *ptr = nv->value;
+ int i;
+
+ if (strcasecmp (ptr, "any") == 0) {
+ config->local_port = 0;
+ return 0;
+ }
+
+ /* check that all chars are numbers */
+ for (i=0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ syslog(LOG_ERR,
+ "Value %s should only be numbers - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ syslog(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ /* Check its range */
+ if (i > INT_MAX) {
+ syslog(LOG_ERR,
+ "Error - converted number (%s) is too large - line %d",
+ nv->value, line);
+ return 1;
+ }
+ config->local_port = (unsigned int)i;
+ return 0;
+}
+
static int transport_parser(struct nv_pair *nv, int line, remote_conf_t *config)
{
int i;
@@ -477,6 +532,20 @@
return 1;
}
+static int format_parser(struct nv_pair *nv, int line,
+ remote_conf_t *config)
+{
+ int i;
+ for (i=0; format_words[i].name != NULL; i++) {
+ if (strcasecmp(nv->value, format_words[i].name) == 0) {
+ config->format = format_words[i].option;
+ return 0;
+ }
+ }
+ syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line);
+ return 1;
+}
+
/*
* This function is where we do the integrated check of the audispd config
* options. At this point, all fields have been read. Returns 0 if no
diff -N -U 3 -x .svn -r pristine/audisp/plugins/remote/remote-config.h trunk/audisp/plugins/remote/remote-config.h
--- pristine/audisp/plugins/remote/remote-config.h 2008-08-04 12:47:28.000000000 -0400
+++ trunk/audisp/plugins/remote/remote-config.h 2008-08-13 22:17:19.000000000 -0400
@@ -27,16 +27,19 @@
typedef enum { M_IMMEDIATE, M_STORE_AND_FORWARD } mode_t;
typedef enum { T_TCP, T_SSL, T_GSSAPI, T_LABELED } transport_t;
typedef enum { F_IGNORE, F_SYSLOG, F_EXEC, F_SUSPEND, F_SINGLE, F_HALT } fail_t;
+typedef enum { F_ASCII, F_MANAGED } format_t;
typedef struct remote_conf
{
const char *remote_server;
unsigned int port;
+ unsigned int local_port;
transport_t transport;
mode_t mode;
unsigned int queue_depth;
fail_t fail_action;
const char *fail_exe;
+ format_t format;
} remote_conf_t;
void clear_config(remote_conf_t *config);
diff -N -U 3 -x .svn -r pristine/docs/auditd.conf.5 trunk/docs/auditd.conf.5
--- pristine/docs/auditd.conf.5 2008-08-04 12:47:31.000000000 -0400
+++ trunk/docs/auditd.conf.5 2008-08-14 15:35:29.000000000 -0400
@@ -212,6 +212,26 @@
option will cause the audit daemon to put the computer system in single user mode.
.I halt
option will cause the audit daemon to shutdown the computer system.
+.TP
+.I tcp_listen_port
+This is a numeric value in the range 1..65535 which, if specified,
+causes auditd to listen on the corresponding TCP port for audit
+records from remote systems.
+.TP
+.I tcp_listen_queue
+This is a numeric value which indicates how many pending (requested
+but unaccepted) connections are allowed. The default is 5. Setting
+this too small may cause connections to be rejected if too many hosts
+start up at exactly the same time, such as after a power failure.
+.TP
+.I tcp_client_ports
+This parameter may be a single numeric value or two values separated
+by a dash (no spaces allowed). It indicates which client ports are
+allowed for incoming connections. If not specified, any port is
+allowed. Allowed values are 1..65535. For example, to require the
+client use a priviledged port, specify
+.I 1-1023
+for this parameter.
.SH NOTES
In a CAPP environment, the audit trail is considered so important that access to system resources must be denied if an audit trail cannot be created. In this environment, it would be suggested that /var/log/audit be on its own partition. This is to ensure that space detection is accurate and that no other process comes along and consumes part of it.
@@ -227,6 +247,11 @@
The disk_full_action is triggered when no more room exists on the partition. All access should be terminated since no more audit capability exists. This can be set to either single or halt.
.PP
The disk_error_action should be set to syslog, single, or halt depending on your local policies regarding handling of hardware malfunctions.
+.PP
+Specifying a single allowed client port may make it difficult for the
+client to restart their audit subsystem, as it will be unable to
+recreate a connection with the same host addresses and ports until the
+connection closure TIME_WAIT state times out.
.SH FILES
.TP
diff -N -U 3 -x .svn -r pristine/init.d/auditd.conf trunk/init.d/auditd.conf
--- pristine/init.d/auditd.conf 2008-08-04 12:47:28.000000000 -0400
+++ trunk/init.d/auditd.conf 2008-08-14 15:22:08.000000000 -0400
@@ -22,4 +22,6 @@
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND
-
+#tcp_listen_port =
+#tcp_listen_queue = 5
+#tcp_client_ports = 1024-65535
diff -N -U 3 -x .svn -r pristine/lib/libaudit.h trunk/lib/libaudit.h
--- pristine/lib/libaudit.h 2008-08-04 12:47:34.000000000 -0400
+++ trunk/lib/libaudit.h 2008-08-14 10:58:46.000000000 -0400
@@ -413,10 +413,6 @@
};
};
-struct auditd_reply_list {
- struct audit_reply reply;
- struct auditd_reply_list *next;
-};
//
// End of ABI control
//////////////////////////////////////////////////////
diff -N -U 3 -x .svn -r pristine/lib/private.h trunk/lib/private.h
--- pristine/lib/private.h 2008-08-04 12:47:34.000000000 -0400
+++ trunk/lib/private.h 2008-08-14 10:58:46.000000000 -0400
@@ -55,6 +55,83 @@
;
#endif
+/* This structure is for protocol reference only. All fields are
+ packed and in network order (LSB first). */
+struct auditd_remote_message_wrapper {
+ /* The magic number shall never have LF (0x0a) as one of its bytes. */
+ uint32_t magic;
+ /* Bumped when the layout of this structure changes. */
+ uint8_t header_version;
+ /* The minimum support needed to understand this message type.
+ * Normally zero. */
+ uint8_t message_version;
+ /* Upper 8 bits are generic type, see below. */
+ uint32_t type;
+ /* Number of bytes that follow this header Must be 0..MAX_AUDIT_MESSAGE_LENGTH. */
+ uint16_t length;
+ /* Copied from message to its reply. */
+ uint32_t sequence_id;
+ /* The message follows for LENGTH bytes. */
+};
+
+#define AUDIT_RMW_HEADER_SIZE 16
+/* The magic number shall never have LF (0x0a) as one of its bytes. */
+#define AUDIT_RMW_MAGIC 0xff0000feUL
+
+#define AUDIT_RMW_HEADER_VERSION 0
+
+/* If set, this is a reply. */
+#define AUDIT_RMW_TYPE_REPLYMASK 0x40000000
+/* If set, this reply indicates a fatal error of some sort. */
+#define AUDIT_RMW_TYPE_FATALMASK 0x20000000
+/* If set, this reply indicates success but with some warnings. */
+#define AUDIT_RMW_TYPE_WARNMASK 0x10000000
+/* This part of the message type is the details for the above. */
+#define AUDIT_RMW_TYPE_DETAILMASK 0x0fffffff
+
+/* Version 0 messages. */
+#define AUDIT_RMW_TYPE_MESSAGE 0x00000000
+#define AUDIT_RMW_TYPE_ACK 0x40000000
+#define AUDIT_RMW_TYPE_ENDING 0x40000001
+#define AUDIT_RMW_TYPE_DISKLOW 0x50000001
+#define AUDIT_RMW_TYPE_DISKFULL 0x60000001
+#define AUDIT_RMW_TYPE_DISKERROR 0x60000002
+
+/* These next four should not be called directly. */
+#define _AUDIT_RMW_PUTN32(header,i,v) \
+ header[i] = v & 0xff; \
+ header[i+1] = (v>>8) & 0xff; \
+ header[i+2] = (v>>16) & 0xff; \
+ header[i+3] = (v>>24) & 0xff;
+#define _AUDIT_RMW_PUTN16(header,i,v) \
+ header[i] = v & 0xff; \
+ header[i+1] = (v>>8) & 0xff;
+#define _AUDIT_RMW_GETN32(header,i) \
+ (header[i] | (header[i+1]<<8) | (header[i+2]<<16) | (header[i+3]<<24))
+#define _AUDIT_RMW_GETN16(header,i) \
+ (header[i] | (header[i+1]<<8))
+
+/* For these, HEADER must by of type "unsigned char *" or "unsigned
+ char []" */
+
+#define AUDIT_RMW_PACK_HEADER(header,mver,type,len,seq) \
+ _AUDIT_RMW_PUTN32 (header,0, AUDIT_RMW_MAGIC); \
+ header[4] = AUDIT_RMW_HEADER_VERSION; \
+ header[5] = mver; \
+ _AUDIT_RMW_PUTN32 (header,6, type); \
+ _AUDIT_RMW_PUTN16 (header,10, len); \
+ _AUDIT_RMW_PUTN32 (header,12, seq);
+
+#define AUDIT_RMW_IS_MAGIC(header,length) \
+ (length >= 4 && _AUDIT_RMW_GETN32 (header,0) == AUDIT_RMW_MAGIC)
+
+#define AUDIT_RMW_UNPACK_HEADER(header,hver,mver,type,len,seq) \
+ hver = header[4]; \
+ mver = header[5]; \
+ type = _AUDIT_RMW_GETN32 (header,6); \
+ len = _AUDIT_RMW_GETN16 (header,10); \
+ seq = _AUDIT_RMW_GETN32 (header,12);
+
/* General */
extern int audit_send(int fd, int type, const void *data, unsigned int size)
hidden;
diff -N -U 3 -x .svn -r pristine/src/Makefile.am trunk/src/Makefile.am
--- pristine/src/Makefile.am 2008-08-07 21:18:16.000000000 -0400
+++ trunk/src/Makefile.am 2008-08-08 16:41:07.000000000 -0400
@@ -27,9 +27,9 @@
LIBS = -Lmt -lauditmt -Llibev -lev -lrt -lm
LDADD = -lpthread
AM_CFLAGS = -D_REENTRANT -D_GNU_SOURCE
-noinst_HEADERS = auditd-config.h auditd-event.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h
+noinst_HEADERS = auditd-config.h auditd-event.h auditd-listen.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h
-auditd_SOURCES = auditd.c auditd-event.c auditd-config.c auditd-reconfig.c auditd-sendmail.c auditd-dispatch.c
+auditd_SOURCES = auditd.c auditd-event.c auditd-config.c auditd-reconfig.c auditd-sendmail.c auditd-dispatch.c auditd-listen.c
auditd_CFLAGS = -fPIE -DPIE -g -D_REENTRANT -D_GNU_SOURCE
auditd_LDFLAGS = -pie -Wl,-z,relro
auditd_DEPENDENCIES = mt/libauditmt.a libev/libev.a
diff -N -U 3 -x .svn -r pristine/src/auditd-config.c trunk/src/auditd-config.c
--- pristine/src/auditd-config.c 2008-08-07 17:32:20.000000000 -0400
+++ trunk/src/auditd-config.c 2008-08-08 15:56:13.000000000 -0400
@@ -39,6 +39,8 @@
#include "libaudit.h"
#include "private.h"
+#define TCP_PORT_MAX 65535
+
/* Local prototypes */
struct nv_pair
{
@@ -103,6 +105,12 @@
struct daemon_conf *config);
static int priority_boost_parser(struct nv_pair *nv, int line,
struct daemon_conf *config);
+static int tcp_listen_port_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config);
+static int tcp_listen_queue_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config);
+static int tcp_client_ports_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config);
static int sanity_check(struct daemon_conf *config);
static const struct kw_pair keywords[] =
@@ -127,6 +135,9 @@
{"disk_full_action", disk_full_action_parser, 1 },
{"disk_error_action", disk_error_action_parser, 1 },
{"priority_boost", priority_boost_parser, 0 },
+ {"tcp_listen_port", tcp_listen_port_parser, 0 },
+ {"tcp_listen_queue", tcp_listen_queue_parser, 0 },
+ {"tcp_client_ports", tcp_client_ports_parser, 0 },
{ NULL, NULL }
};
@@ -227,6 +238,10 @@
config->disk_full_exe = NULL;
config->disk_error_action = FA_SYSLOG;
config->disk_error_exe = NULL;
+ config->tcp_listen_port = 0;
+ config->tcp_listen_queue = 5;
+ config->tcp_client_min_port = 0;
+ config->tcp_client_max_port = TCP_PORT_MAX;
}
static log_test_t log_test = TEST_AUDITD;
@@ -1109,6 +1124,172 @@
return 0;
}
+static int tcp_listen_port_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config)
+{
+ const char *ptr = nv->value;
+ unsigned long i;
+
+ audit_msg(LOG_DEBUG, "tcp_listen_port_parser called with: %s",
+ nv->value);
+
+ /* check that all chars are numbers */
+ for (i=0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ /* Check its range */
+ if (i > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too large - line %d",
+ nv->value, line);
+ return 1;
+ }
+ if (i < 1) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too small - line %d",
+ nv->value, line);
+ return 1;
+ }
+ config->tcp_listen_port = (unsigned int)i;
+ return 0;
+}
+
+static int tcp_listen_queue_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config)
+{
+ const char *ptr = nv->value;
+ unsigned long i;
+
+ audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s",
+ nv->value);
+
+ /* check that all chars are numbers */
+ for (i=0; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ i = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ /* Check its range. While this value is technically
+ unlimited, it's limited by the kernel, and we limit it here
+ for sanity. */
+ if (i > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too large - line %d",
+ nv->value, line);
+ return 1;
+ }
+ if (i < 1) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%s) is too small - line %d",
+ nv->value, line);
+ return 1;
+ }
+ config->tcp_listen_queue = (unsigned int)i;
+ return 0;
+}
+
+static int tcp_client_ports_parser(struct nv_pair *nv, int line,
+ struct daemon_conf *config)
+{
+ const char *ptr = nv->value;
+ unsigned long i, minv, maxv;
+ const char *saw_dash = NULL;
+
+ audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s",
+ nv->value);
+
+ /* check that all chars are numbers, with an optional inclusive '-'. */
+ for (i=0; ptr[i]; i++) {
+ if (i > 0 && ptr[i] == '-' && ptr[i+1] != '\0') {
+ saw_dash = ptr + i;
+ continue;
+ }
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers, or two numbers separated by a dash - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+ for (; ptr[i]; i++) {
+ if (!isdigit(ptr[i])) {
+ audit_msg(LOG_ERR,
+ "Value %s should only be numbers, or two numbers separated by a dash - line %d",
+ nv->value, line);
+ return 1;
+ }
+ }
+
+ /* convert to unsigned int */
+ errno = 0;
+ maxv = minv = strtoul(nv->value, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ if (saw_dash) {
+ maxv = strtoul(saw_dash + 1, NULL, 10);
+ if (errno) {
+ audit_msg(LOG_ERR,
+ "Error converting string to a number (%s) - line %d",
+ strerror(errno), line);
+ return 1;
+ }
+ }
+ /* Check their ranges. */
+ if (minv > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%d) is too large - line %d",
+ minv, line);
+ return 1;
+ }
+ if (maxv > TCP_PORT_MAX) {
+ audit_msg(LOG_ERR,
+ "Error - converted number (%d) is too large - line %d",
+ maxv, line);
+ return 1;
+ }
+ if (minv > maxv) {
+ audit_msg(LOG_ERR,
+ "Error - converted range (%d-%d) is reversed - line %d",
+ minv, maxv, line);
+ return 1;
+ }
+ config->tcp_client_min_port = (unsigned int)minv;
+ config->tcp_client_max_port = (unsigned int)maxv;
+ return 0;
+}
+
/*
* This function is where we do the integrated check of the audit config
* options. At this point, all fields have been read. Returns 0 if no
diff -N -U 3 -x .svn -r pristine/src/auditd-config.h trunk/src/auditd-config.h
--- pristine/src/auditd-config.h 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-config.h 2008-08-14 15:33:28.000000000 -0400
@@ -70,6 +70,10 @@
const char *disk_full_exe;
failure_action_t disk_error_action;
const char *disk_error_exe;
+ unsigned long tcp_listen_port;
+ unsigned long tcp_listen_queue;
+ unsigned long tcp_client_min_port;
+ unsigned long tcp_client_max_port;
};
void set_allow_links(int allow);
@@ -80,7 +84,9 @@
int resolve_node(struct daemon_conf *config);
void init_config_manager(void);
+#ifdef AUDITD_EVENT_H
int start_config_manager(struct auditd_reply_list *rep);
+#endif
void shutdown_config(void);
void free_config(struct daemon_conf *config);
diff -N -U 3 -x .svn -r pristine/src/auditd-event.c trunk/src/auditd-event.c
--- pristine/src/auditd-event.c 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-event.c 2008-08-13 21:56:24.000000000 -0400
@@ -148,6 +148,36 @@
dequeue'r is responsible for freeing the memory. */
void enqueue_event(struct auditd_reply_list *rep)
{
+ char *buf;
+ int len;
+
+ rep->ack_socket = 0;
+ rep->sequence_id = 0;
+
+ switch (consumer_data.config->log_format)
+ {
+ case LF_RAW:
+ buf = format_raw(&rep->reply, consumer_data.config);
+ break;
+ case LF_NOLOG:
+ return;
+ default:
+ audit_msg(LOG_ERR,
+ "Illegal log format detected %d",
+ consumer_data.config->log_format);
+ return;
+ }
+
+ len = strlen (buf);
+ if (len < MAX_AUDIT_MESSAGE_LENGTH - 1)
+ memcpy (rep->reply.msg.data, buf, len+1);
+ else
+ {
+ /* FIXME: is truncation the right thing to do? */
+ memcpy (rep->reply.msg.data, buf, MAX_AUDIT_MESSAGE_LENGTH-1);
+ rep->reply.msg.data[MAX_AUDIT_MESSAGE_LENGTH-1] = 0;
+ }
+
rep->next = NULL; /* new packet goes at end - so zero this */
pthread_mutex_lock(&consumer_data.queue_lock);
@@ -164,6 +194,45 @@
pthread_mutex_unlock(&consumer_data.queue_lock);
}
+/* This function takes a preformatted message and places it on the
+ queue. The dequeue'r is responsible for freeing the memory. */
+void enqueue_formatted_event(char *msg, int ack_socket, uint32_t sequence_id)
+{
+ int len;
+ struct auditd_reply_list *rep;
+
+ rep = (struct auditd_reply_list *) calloc (1, sizeof (*rep));
+ if (rep == NULL) {
+ audit_msg(LOG_ERR, "Cannot allocate audit reply");
+ return;
+ }
+
+ rep->ack_socket = ack_socket;
+ rep->sequence_id = sequence_id;
+
+ len = strlen (msg);
+ if (len < MAX_AUDIT_MESSAGE_LENGTH - 1)
+ memcpy (rep->reply.msg.data, msg, len+1);
+ else {
+ /* FIXME: is truncation the right thing to do? */
+ memcpy (rep->reply.msg.data, msg, MAX_AUDIT_MESSAGE_LENGTH-1);
+ rep->reply.msg.data[MAX_AUDIT_MESSAGE_LENGTH-1] = 0;
+ }
+
+ pthread_mutex_lock(&consumer_data.queue_lock);
+ if (consumer_data.head == NULL) {
+ consumer_data.head = consumer_data.tail = rep;
+ pthread_cond_signal(&consumer_data.queue_nonempty);
+ } else {
+ /* FIXME: wait for room on the queue */
+
+ /* OK there's room...add it in */
+ consumer_data.tail->next = rep; /* link in at end */
+ consumer_data.tail = rep; /* move end to newest */
+ }
+ pthread_mutex_unlock(&consumer_data.queue_lock);
+}
+
void resume_logging(void)
{
logging_suspended = 0;
@@ -233,30 +302,8 @@
rotate_logs_now(data);
}
if (!logging_suspended) {
- char *buf = NULL;
-
- switch (data->config->log_format)
- {
- case LF_RAW:
- buf = format_raw(&data->head->reply,
- data->config);
- break;
- case LF_NOLOG:
- return;
- default:
- audit_msg(LOG_ERR,
- "Illegal log format detected %d",
- data->config->log_format);
- break;
- }
- /* The only way buf is NULL is if there is an
- * unidentified format...which is impossible since
- * start up would have failed. */
- if (buf) {
- write_to_log(buf, data);
- buf[0] = 0;
- }
+ write_to_log(data->head->reply.msg.data, data);
/* See if we need to flush to disk manually */
if (data->config->flush == FT_INCREMENTAL) {
@@ -289,12 +336,32 @@
}
}
+static int ar_write (int sock, const void *buf, int len)
+{
+ int rc = 0, w;
+ while (len > 0) {
+ do {
+ w = write(sock, buf, len);
+ } while (w < 0 && errno == EINTR);
+ if (w < 0)
+ return w;
+ if (w == 0)
+ break;
+ rc += w;
+ len -= w;
+ buf = (const void *)((const char *)buf + w);
+ }
+ return rc;
+}
+
/* This function writes the given buf to the current log file */
static void write_to_log(const char *buf, struct auditd_consumer_data *data)
{
int rc;
FILE *f = data->log_file;
struct daemon_conf *config = data->config;
+ int ack_type = AUDIT_RMW_TYPE_ACK;
+ const char *msg = "";
/* write it to disk */
rc = fprintf(f, "%s\n", buf);
@@ -307,20 +374,35 @@
if (saved_errno == ENOSPC && fs_space_left == 1) {
fs_space_left = 0;
do_disk_full_action(config);
- } else
+ ack_type = AUDIT_RMW_TYPE_DISKFULL;
+ msg = "disk full";
+ } else {
do_disk_error_action("write", config);
+ ack_type = AUDIT_RMW_TYPE_DISKERROR;
+ msg = "disk write error";
+ }
+
+ } else {
- return;
+ /* check log file size & space left on partition */
+ if (config->daemonize == D_BACKGROUND) {
+ // If either of these fail, I consider it an inconvenience
+ // as opposed to something that is actionable. There may be
+ // some temporary condition that the system recovers from.
+ // The real error occurs on write.
+ check_log_file_size(data->log_fd, data);
+ check_space_left(data->log_fd, config);
+ }
}
- /* check log file size & space left on partition */
- if (config->daemonize == D_BACKGROUND) {
- // If either of these fail, I consider it an inconvenience
- // as opposed to something that is actionable. There may be
- // some temporary condition that the system recovers from.
- // The real error occurs on write.
- check_log_file_size(data->log_fd, data);
- check_space_left(data->log_fd, config);
+ if (data->head->ack_socket) {
+ unsigned char header[AUDIT_RMW_HEADER_SIZE];
+
+ AUDIT_RMW_PACK_HEADER (header, 0, ack_type, strlen(msg), data->head->sequence_id);
+
+ ar_write (data->head->ack_socket, header, AUDIT_RMW_HEADER_SIZE);
+ if (msg[0])
+ ar_write (data->head->ack_socket, msg, strlen(msg));
}
}
diff -N -U 3 -x .svn -r pristine/src/auditd-event.h trunk/src/auditd-event.h
--- pristine/src/auditd-event.h 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-event.h 2008-08-13 20:41:41.000000000 -0400
@@ -25,12 +25,21 @@
#define AUDITD_EVENT_H
#include "libaudit.h"
+
+struct auditd_reply_list {
+ struct audit_reply reply;
+ struct auditd_reply_list *next;
+ int ack_socket;
+ unsigned long sequence_id;
+};
+
#include "auditd-config.h"
void shutdown_events(void);
int init_event(struct daemon_conf *config);
void resume_logging(void);
void enqueue_event(struct auditd_reply_list *rep);
+void enqueue_formatted_event(char *msg, int ack_socket, uint32_t sequence_id);
void *consumer_thread_main(void *arg);
#endif
diff -N -U 3 -x .svn -r pristine/src/auditd-listen.c trunk/src/auditd-listen.c
--- pristine/src/auditd-listen.c 1969-12-31 19:00:00.000000000 -0500
+++ trunk/src/auditd-listen.c 2008-08-13 22:29:22.000000000 -0400
@@ -0,0 +1,335 @@
+/* auditd-listen.c --
+ * Copyright 2008 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ * DJ Delorie <dj(a)redhat.com>
+ *
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <fcntl.h> /* O_NOFOLLOW needs gnu defined */
+#include <libgen.h>
+#include <arpa/inet.h>
+#include <limits.h> /* INT_MAX */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include "libaudit.h"
+#include "auditd-event.h"
+#include "auditd-config.h"
+#include "private.h"
+
+#include "ev.h"
+
+extern volatile int stop;
+
+typedef struct ev_tcp {
+ struct ev_io io;
+ struct sockaddr_in addr;
+ struct ev_tcp *next, *prev;
+ int bufptr;
+ unsigned char buffer [MAX_AUDIT_MESSAGE_LENGTH + 17];
+} ev_tcp;
+
+static int listen_socket;
+static struct ev_io tcp_listen_watcher;
+static int min_port, max_port;
+
+static struct ev_tcp *client_chain = 0;
+
+static char *sockaddr_to_ip (struct sockaddr_in *addr)
+{
+ unsigned char *uaddr = (unsigned char *)&(addr->sin_addr);
+ static char buf[40];
+
+ sprintf (buf, "%d.%d.%d.%d:%d",
+ uaddr[0], uaddr[1], uaddr[2], uaddr[3], ntohs (addr->sin_port));
+ return buf;
+}
+
+static void set_close_on_exec (int fd)
+{
+ int flags = fcntl (fd, F_GETFD);
+ if (flags == -1)
+ flags = 0;
+ flags |= FD_CLOEXEC;
+ fcntl (fd, F_SETFD, flags);
+}
+
+static void close_client (struct ev_tcp *client)
+{
+ close (client->io.fd);
+ if (client_chain == client)
+ client_chain = client->next;
+ if (client->next)
+ client->next->prev = client->prev;
+ if (client->prev)
+ client->prev->next = client->next;
+ free (client);
+}
+
+static void client_message (struct ev_tcp *io, unsigned int length, unsigned char *header)
+{
+ unsigned char ch;
+ uint32_t magic, type, mlen, seq;
+ int hver, mver;
+ int i;
+
+ if (AUDIT_RMW_IS_MAGIC (header, length)) {
+ AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, mlen, seq)
+
+ ch = header[length];
+ header[length] = 0;
+ if (length > 1 && header[length-1] == '\n')
+ header[length-1] = 0;
+ enqueue_formatted_event (header+AUDIT_RMW_HEADER_SIZE, io->io.fd, seq);
+ header[length] = ch;
+ } else {
+ header[length] = 0;
+ if (length > 1 && header[length-1] == '\n')
+ header[length-1] = 0;
+ enqueue_formatted_event (header, 0, 0);
+ }
+}
+
+static void auditd_tcp_client_handler( struct ev_loop *loop, struct ev_io *_io, int revents )
+{
+ struct ev_tcp *io = (struct ev_tcp *) _io;
+ int i, r;
+ int total_this_call = 0;
+
+ /* The socket is non-blocking, but we have a limited buffer
+ size. In the event that we get a packet that's bigger than
+ our buffer, we need to read it in multiple parts. Thus, we
+ keep reading/parsing/processing until we run out of ready
+ data. */
+read_more:
+ r = read (io->io.fd,
+ io->buffer + io->bufptr,
+ MAX_AUDIT_MESSAGE_LENGTH - io->bufptr);
+
+ if (r < 0 && errno == EAGAIN)
+ r = 0;
+
+ /* We need to keep track of the difference between "no data
+ * because it's closed" and "no data because we've read it
+ * all". */
+ if (r == 0 && total_this_call > 0) {
+ return;
+ }
+
+ /* If the connection is gracefully closed, the first read we
+ try will return zero. If the connection times out or
+ otherwise fails, the read will return -1. */
+ if (r <= 0) {
+ if (r < 0)
+ audit_msg (LOG_WARNING, "client %s socket closed unexpectedly",
+ sockaddr_to_ip (&io->addr));
+
+ /* There may have been a final message without a LF. */
+ if (io->bufptr) {
+ client_message (io, io->bufptr, io->buffer);
+
+ }
+
+ ev_io_stop (loop, _io);
+ close_client (io);
+ return;
+ }
+
+ total_this_call += r;
+
+more_messages:
+ if (AUDIT_RMW_IS_MAGIC (io->buffer, io->bufptr+r)) {
+ uint32_t type, len, seq;
+ int hver, mver;
+ unsigned char *header = (unsigned char *)io->buffer;
+
+ io->bufptr += r;
+
+ if (io->bufptr < AUDIT_RMW_HEADER_SIZE)
+ return;
+
+ AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, len, seq);
+
+ i = len;
+ i += AUDIT_RMW_HEADER_SIZE;
+
+ /* See if we have enough bytes to extract the whole message. */
+ if (io->bufptr < i)
+ return;
+
+ } else {
+ /* At this point, the buffer has IO->BUFPTR+R bytes in it.
+ The first IO->BUFPTR bytes do not have a LF in them (we've
+ already checked), we must check the R new bytes. */
+
+ for (i = io->bufptr; i < io->bufptr + r; i ++)
+ if (io->buffer [i] == '\n')
+ break;
+
+ io->bufptr += r;
+
+ /* Check for a partial message, with no LF yet. */
+ if (i == io->bufptr)
+ return;
+
+ i ++;
+ }
+
+ /* We have an I-byte message in buffer. */
+ client_message (io, i, io->buffer);
+
+ /* Now copy any remaining bytes to the beginning of the
+ buffer. */
+ memmove (io->buffer, io->buffer + i, io->bufptr);
+ io->bufptr -= i;
+
+ /* See if this packet had more than one message in it. */
+ if (io->bufptr > 0) {
+ r = io->bufptr;
+ io->bufptr = 0;
+ goto more_messages;
+ }
+
+ /* Go back and see if there's more data to read. */
+ goto read_more;
+}
+
+static void auditd_tcp_listen_handler( struct ev_loop *loop, struct ev_io *_io, int revents )
+{
+ int one=1;
+ int afd;
+ socklen_t aaddrlen;
+ struct sockaddr_in aaddr;
+ struct linger li;
+ struct ev_tcp *client;
+ unsigned char *uaddr;
+
+ /* Accept the connection and see where it's coming from. */
+ aaddrlen = sizeof(aaddr);
+ afd = accept (listen_socket, (struct sockaddr *)&aaddr, &aaddrlen);
+ if (afd == -1) {
+ audit_msg(LOG_ERR, "Unable to accept TCP connection");
+ return;
+ }
+
+ uaddr = (unsigned char *)&aaddr.sin_addr;
+
+ /* Verify it's coming from an authorized port. We assume the firewall will
+ block attempts from unauthorized machines. */
+ if (min_port > ntohs (aaddr.sin_port) || ntohs (aaddr.sin_port) > max_port) {
+ audit_msg(LOG_ERR, "TCP connection from %s rejected", sockaddr_to_ip (&aaddr));
+ close (afd);
+ return;
+ }
+
+ setsockopt(afd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+ setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (int));
+ setsockopt(afd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int));
+ fcntl(afd, F_SETFL, O_NONBLOCK | O_NDELAY);
+ set_close_on_exec (afd);
+
+ client = (struct ev_tcp *) malloc (sizeof (struct ev_tcp));
+ if (client == NULL) {
+ audit_msg(LOG_CRIT, "Unable to allocate TCP client data");
+ close (afd);
+ return;
+ }
+
+ memset (client, 0, sizeof (struct ev_tcp));
+
+ ev_io_init (&(client->io), auditd_tcp_client_handler, afd, EV_READ | EV_ERROR);
+ ev_io_start (loop, &(client->io));
+
+ memcpy (&client->addr, &aaddr, sizeof (struct sockaddr_in));
+
+ /* Keep a linked list of active clients. */
+ client->next = client_chain;
+ if (client->next)
+ client->next->prev = client;
+ client_chain = client;
+}
+
+int auditd_tcp_listen_init ( struct ev_loop *loop, struct daemon_conf *config )
+{
+ struct sockaddr_in address;
+ int one = 1;
+ int flags;
+
+ /* If the port is not set, that means we aren't going to
+ listen for connections. */
+ if (config->tcp_listen_port == 0)
+ return;
+
+ listen_socket = socket (AF_INET, SOCK_STREAM, 0);
+ if (listen_socket == 0) {
+ audit_msg(LOG_ERR, "Cannot create tcp listener socket");
+ return 1;
+ }
+
+ set_close_on_exec (listen_socket);
+ setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+
+ memset (&address, 0, sizeof(address));
+ address.sin_family = htons(AF_INET);
+ address.sin_port = htons(config->tcp_listen_port);
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ /* This avoids problems if auditd needs to be restarted. */
+ setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int));
+
+ if ( bind ( listen_socket, (struct sockaddr *)&address, sizeof(address)) ) {
+ audit_msg(LOG_ERR, "Cannot bind tcp listener socket to port %d",
+ config->tcp_listen_port);
+ close(listen_socket);
+ return 1;
+ }
+
+ listen(listen_socket, config->tcp_listen_queue);
+
+ audit_msg(LOG_DEBUG, "Listening on TCP port %d", config->tcp_listen_port);
+
+ ev_io_init (&tcp_listen_watcher, auditd_tcp_listen_handler, listen_socket, EV_READ);
+ ev_io_start (loop, &tcp_listen_watcher);
+
+ min_port = config->tcp_client_min_port;
+ max_port = config->tcp_client_max_port;
+
+ return 0;
+}
+
+void auditd_tcp_listen_uninit ( struct ev_loop *loop )
+{
+ ev_io_stop ( loop, &tcp_listen_watcher );
+ close ( listen_socket );
+
+ while (client_chain) {
+ close_client (client_chain);
+ }
+}
diff -N -U 3 -x .svn -r pristine/src/auditd-listen.h trunk/src/auditd-listen.h
--- pristine/src/auditd-listen.h 1969-12-31 19:00:00.000000000 -0500
+++ trunk/src/auditd-listen.h 2008-08-08 17:01:37.000000000 -0400
@@ -0,0 +1,30 @@
+/* auditd-config.h --
+ * Copyright 2004-2007 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ * DJ Delorie <dj(a)redhat.com>
+ *
+ */
+
+#ifndef AUDITD_LISTEN_H
+#define AUDITD_LISTEN_H
+
+int auditd_tcp_listen_init ( struct ev_loop *loop, struct daemon_conf *config );
+void auditd_tcp_listen_uninit ( struct ev_loop *loop );
+
+#endif
diff -N -U 3 -x .svn -r pristine/src/auditd-reconfig.c trunk/src/auditd-reconfig.c
--- pristine/src/auditd-reconfig.c 2008-08-04 12:47:30.000000000 -0400
+++ trunk/src/auditd-reconfig.c 2008-08-12 18:54:20.000000000 -0400
@@ -28,9 +28,9 @@
#include <unistd.h>
#include <string.h>
#include <stdio.h>
-#include "auditd-config.h"
-#include "auditd-event.h"
#include "libaudit.h"
+#include "auditd-event.h"
+#include "auditd-config.h"
#include "private.h"
/* This is the configuration manager code */
diff -N -U 3 -x .svn -r pristine/src/auditd.c trunk/src/auditd.c
--- pristine/src/auditd.c 2008-08-08 14:36:19.000000000 -0400
+++ trunk/src/auditd.c 2008-08-13 20:51:35.000000000 -0400
@@ -40,8 +40,8 @@
#include <getopt.h>
#include "libaudit.h"
-#include "auditd-config.h"
#include "auditd-event.h"
+#include "auditd-config.h"
#include "auditd-dispatch.h"
#include "private.h"
@@ -670,7 +670,15 @@
ev_signal_init (&sigchld_watcher, child_handler, SIGCHLD);
ev_signal_start (loop, &sigchld_watcher);
- ev_loop (loop, 0);
+ if (auditd_tcp_listen_init (loop, &config)) {
+ tell_parent (FAILURE);
+ stop = 1;
+ }
+
+ if (!stop)
+ ev_loop (loop, 0);
+
+ auditd_tcp_listen_uninit (loop);
/* Write message to log that we are going down */
15 years, 3 months
[RFC] Drop support for old audit rule API
by Steve Grubb
Hi,
Another thought for the next major release is to drop support for the old
audit rules API in libaudit. A long time ago, the function prototypes for:
extern int audit_request_rules_list(int fd);
extern int audit_add_rule(int fd, struct audit_rule *rule,
int flags, int action);
extern int audit_delete_rule(int fd, struct audit_rule *rule,
int flags, int action);
extern int audit_rule_syscall(struct audit_rule *rule, int scall);
extern int audit_rule_syscallbyname(struct audit_rule *rule,
const char *scall);
extern int audit_rule_fieldpair(struct audit_rule *rule, const char *pair,
int flags);
extern void audit_rule_free(struct audit_rule *rule);
Were moved to a private internal header. This was to encourage any external
apps from using them, but if they had been previously compiled to know about
the API, they would still be able to link and run.
As far as I know, auditctl & autrace are the only apps that would be affected.
There very well may be some 3rd party apps I don't know about that this could
impact. Hopefully they are on this list or moved their function calls when
the prototype disappeared.
The proposal is to drop the above mentioned functions and bump the soname
number so that anything linking against libaudit has to be recompiled to make
sure they have no old function calls. At some point in the future, we can
also remove the kernel's support for the old rule format.
Let's discuss....
-Steve
15 years, 5 months
[RFC] Do away with entry filter
by Steve Grubb
Hello,
I will be forking the user space audit code soon to start the next major
series. I have a couple thoughts I'd like to share with people to see what
they think.
The first item is doing away with the entry filter for syscall auditing. You
normally run across this filter when you write rules such as:
-a always,entry -S open
The reason I think we can do away with it is that its purpose has changed. Way
back in the early days 2.6.6 -> 2.6.15 kernels, there was this notion that
the audit code could be made to have little impact on the performance of the
system if we give hints about what is needed by using "possible" actions.
The problem with "possible" was that people forgot to use it and had exit
filter rules that had no data to operate on. So, we changed the kernel to
always collect the data it needed in case an exit filter would trigger an
event. This was optimized and performance was pretty good. So, that kind of
left the entry filter without a purpose.
Any entry rule can be written as an exit rule. But not every exit rule can be
written as an entry rule. So the logical choice is to consolidate on the exit
filter. The reason to do this is to improve performance. If we have an entry
rule that triggers, it marks the syscall excursion as auditable. When we get
to the exit filter, it iterates over the whole set of rules even though the
event is auditable. This is because there could be a never rule that would
suppress the output. Another problem introduced by having two filters is that
some fields are not available in the entry filter (exit for example), it adds
complexity in the auditctl program and the in-kernel rule parser to look for
these errors.
The way that we could make the change is for the audit package to silently
convert entry rules to exit in user space. It could output a warning that
entry rules are being converted and the admin should make the necessary
adjustments. Then after some time has elapsed so that distros have all
updated, drop support in the kernel for the entry filter.
Let's discuss...
Thanks,
-Steve
15 years, 5 months
Backwards-compatible string encoding
by Joshua Roys
Hello all,
I have just run into the problem that many of you have: trying to parse
the audit logs.
Yesterday I read through the linux-audit mail archive. Here are the
related topics I have found:
https://www.redhat.com/archives/linux-audit/2006-March/msg00093.html
https://www.redhat.com/archives/linux-audit/2006-March/msg00158.html
https://www.redhat.com/archives/linux-audit/2007-November/msg00036.html
https://www.redhat.com/archives/linux-audit/2008-January/msg00082.html
https://www.redhat.com/archives/linux-audit/2008-March/msg00024.html
https://www.redhat.com/archives/linux-audit/2008-May/msg00029.html
https://www.redhat.com/archives/linux-audit/2008-June/msg00005.html
https://www.redhat.com/archives/linux-audit/2008-August/msg00078.html
https://www.redhat.com/archives/linux-audit/2009-March/msg00018.html
From these I see these requirements (correct me if I am wrong):
- must be backwards-compatible (doesn't break user-space on FC2, etc)
- kernel does no verifying of incoming user-space strings
- kernel must output strings in a "simple" format (e.g. no XML :-)
- able to write a parser that guarantees all (relevant) input ends up in
output
- use disk space efficiently
- handle UTF-8
Based on things other people have proposed, how does this sound:
- radix prefixes for any non-base10 number (I think audit mostly does
this already?)
- hex-encode strings (and do not quote) if:
-- contains non-ASCII or non-printable characters
- quote strings if:
-- contains whitespace or '=' or '"' (in which case you have to output
something like '\"'
-- entirely {hex,octal,base10} characters
Or we could just save a little more headache at the cost of
space/readability and hex-encode on '=' and '"' too. Looking at
auparse, we may have to hexencode with embedded '"'.
Check if you need to encode first, then check for quoting. Something
like...
// somewhere in kernel/audit.c ?
char *audit_log_sane_string(char *str, size_t slen) {
int quoteme = 0;
size_t i, numhex = 0;
for(i = 0; i < slen; i++) {
if (!isprint(str[i])) return(hexencode(str));
if (isspace(str[i]) || str[i] == '=' || str[i] == '"') quoteme = 1;
if (isxdigit(str[i])) numhex++; // xdigit covers base8,10,16
}
if (quoteme || numhex == slen) return(quote(str));
return(strdup(str)); // kstrdup...?
}
Oh, and if anyone has ideas for making shadow-utils play nicer with
audit, I possibly have that kind of time on my hands. Also, getting rid
of the extra punctuation [:(,)] would be great.
What do you all think?
Joshua Roys
15 years, 8 months
[PATCH] Don't crash on unknown S_IFMT file modes
by Miloslav Trmac
Hello,
ausearch -i and libauparse currently crash (access NULL) if a mode= field contains an unknown file type. Such records are generated by the kernel for IPC, e.g.
node=jcdx156 type=IPC msg=audit(1237915952.720:2294): ouid=500 ogid=1106 mode=0600 obj=siterep_u:siterep_r:siterep_t:s0-s15:c0.c1023
The attached patch:
* Modifies ausearch and libauparse to output the file format in octal if it is unknown.
* Modifies libauparse to use the same interpreted field format as ausearch (without a space in the middle).
* Modifies comma handling in libauparse to avoid a strcat() call.
Mirek
15 years, 8 months
Re: [Fwd: [PATCH][RFC] SMACK : add logging support V1]
by Eric Paris
On Mon, 2009-03-30 at 20:30 +0200, Etienne Basset wrote:
> > I didn't look much at all in the SMACK code only the more generic audit
> > code. Are you sure you got the capability no audit stuff right? I
> > guess you would know it pretty quickly since capabilities for memory
> > allocation are checked a LOT, but on OOM and FS full they are checked
> > too.
> >
> I'm not quite sure what you're referring to. You mean a way to not log too much frequent events?
SMACK doesn't have it's own capabilities enforcement (it just calls
cap_capable()) so this doesn't matter to you at all. Just pretend I
didn't say anything.
> > You don't have to but I'd like to see some reworking if you are willing.
> > Any code that you stole line for line from SELinux, lets put that stuff
> > in a single place. I think that's going to mean pretty much all of
> > smack_logging.h could be reasonably moved to a generic header for both
> > of you to use (just make it generic, i'm not asking you to port selinux
> > et al. to the new header.)
>
> OK, would it be something like include/linux/lsm_common_audit.h ?
James? lsm_audit.h? security_audit.h? Should I just shut up and not
try to work towards a generic lsm audit framework? I'm just seeing a
lot of code that I've seen before.
> > I also feel like we could do better reusing
> > code from smack_log and avc_audit but maybe that's beyond what you are
> > willing to try to to take on
> >
>
> you mean doing :
> smack:smack_log(...)
> smack_audit_specific_data()
> ...
> common_security_audit(struct common_audit_data *)
>
> selinux:avc_audit(...)
> selinux_specific_data()
> ...
> common_security_audit(struct common_audit_data *);
>
> It would make sense I guess
I believe they both output the same set of information right? (except
selinux has a tclass smack doesn't?) . But since we can't really
fix/change SELinux logging right now maybe this isn't worth doing too
much work over. If you see an easy way to make more of the code
generic, do it. If not, don't worry about it.
The real difference between the two is in
security/selinux/avc.c::avc_dump_query() vs the beginning of
smack_log(). If it's reasonable to somehow combine most/all of the
other code, i say we do it. This might mean something like
struct selinux_audit_struct {
u32 ssid
u32 tsid
u16 tclass
u32 requested
struct av_decision *avd
int result
}
struct smack_audit_struct {
char *function
int result
char *subj
char *obj
char *requested
}
common_audit_struct {
[everything we have today]
union {
struct selinux_audit_struct selinux_audit;
struct smack_audit_struct smack_audit;
}
void (*lsm_audit)(struct audit_buffer*, void *);
}
So we could call some new generic function that does all of the buffer
allocation and reporting, then call back into the private selinux/smack
function with the data in the union. Maybe this isn't as easy as it
sounded in my head... I just don't think we want a 3,4,5,6
implementations of lsm auditing.
> > I pretty strongly detest %s these days. Using it on the left side of an
> > = is ok if you are REALLY careful. Using it on the right makes me
> > cringe. Can smack labels have characters which are not ascii letters
> > (spaces?)
> >
> no, smack basically do the same tests when importing smack label than you do
> in kernel/audit.c:audit_string_contains_control
> except smack allows the '"' character
How did you plan to handle a SMACK label with a ' ? Using the audit
string functions and being given a label with a " is going to give you
the hex output. (which might someday turn into better encoding, but I'm
still waiting to see some code to do it better)
Can I suggest if you write userspace tools to do anything with these
audit records that you use libauparse? So if we do make changes, SMACK
tools keep working (this is the main problem with changing how SELinux
uses audit, the userspace tools don't use libauparse so we can't make
changes in just the kernel+library...)
-Eric
15 years, 9 months
Re: [Fwd: [PATCH][RFC] SMACK : add logging support V1]
by Casey Schaufler
etienne wrote:
> Hi,
>
> could you have a look at this patch from the audit point of view?
>
> thanks,
> Etienne
>
>
>
>
> Hello,
>
> the following patch, against current 2.6.29-rc7, add logging of smack decisions.
> This is of course very useful to understand what your current smack policy does.
> It borrows a lot from selinux;
>
> It introduces a '/smack/logging' switch :
> 0: no logging
> 1: log denied (default)
> 2: log accepted
> 3: log denied&accepted
>
>
> example of logs produced :
>
> type=1400 audit(1236429348.858:5655879): SMACK[smack_task_kill]: denied pid=6521 comm="bash" subject:'toto' object:'_' requested:w pid=5757 comm="knetworkmanager"
> type=1400 audit(1236429361.477:5655882): SMACK[smk_curacc_shm]: denied pid=6533 comm="ipcrm" subject:'toto' object:'_' requested:rw key=491521
> type=1400 audit(1236429392.389:5655885): SMACK[smack_sb_mount]: denied pid=6536 comm="mount" subject:'toto' object:'_' requested:w path="/debug" dev=sda5 ino=16161
> type=1400 audit(1236429485.009:5655890): SMACK[smack_ptrace_may_access]: denied pid=6539 comm="strace" subject:'toto' object:'_' requested:rw pid=5634 comm="python"
> type=1400 audit(1236429527.693:5655893): SMACK[smack_inode_getattr]: denied pid=6544 comm="ls" subject:'toto' object:'etienne' requested:r path="/home/etienne/linux" dev=sda8 ino=2342913
> type=1400 audit(1236429741.006:6006665): SMACK[smack_socket_sendmsg]: granted pid=6580 comm="ping" subject:'toto' object:'@' requested:w daddr=192.168.0.10
> type=1400 audit(1236429741.006:6006666): SMACK[smack_socket_sock_rcv_skb]: granted pid=6580 comm="ping" subject:'@' object:'toto' requested:w saddr=192.168.0.10 daddr=192.168.0.10 netif=lo
>
>
>
> Signed-off-by: <etienne.basset(a)numericable.fr>
>
Acked-by: Casey Schaufler <casey(a)schaufler-ca.com>
> ---
> Documentation/Smack.txt | 12 +
> security/smack/Kconfig | 2 +-
> security/smack/Makefile | 2 +-
> security/smack/smack_logging.c | 460 ++++++++++++++++++++++++++++++++++++++++
> security/smack/smack_logging.h | 97 +++++++++
> security/smack/smack_lsm.c | 356 +++++++++++++++++++++++--------
> security/smack/smackfs.c | 52 +++++
> 7 files changed, 892 insertions(+), 89 deletions(-)
> ---
> diff --git a/Documentation/Smack.txt b/Documentation/Smack.txt
> index 989c2fc..81a6921 100644
> --- a/Documentation/Smack.txt
> +++ b/Documentation/Smack.txt
> @@ -491,3 +491,15 @@ Smack supports some mount options:
>
> These mount options apply to all file system types.
>
> +Smack logging support
> +
> +Smack supports logging of security accesses. It will log by default all denied
> +requests. The interface to change this behavior is /smack/logging, where you
> +can write the logging level you desire :
> +0: no logging
> +1: log denied (default)
> +2: log accepted
> +3: log denied&accepted
> +
> +Note that due to the rate-limit of audit messages, logging accepted request will
> +drop a lot of messages.
> diff --git a/security/smack/Kconfig b/security/smack/Kconfig
> index 603b087..d83e708 100644
> --- a/security/smack/Kconfig
> +++ b/security/smack/Kconfig
> @@ -1,6 +1,6 @@
> config SECURITY_SMACK
> bool "Simplified Mandatory Access Control Kernel Support"
> - depends on NETLABEL && SECURITY_NETWORK
> + depends on NETLABEL && SECURITY_NETWORK && AUDIT
> default n
> help
> This selects the Simplified Mandatory Access Control Kernel.
> diff --git a/security/smack/Makefile b/security/smack/Makefile
> index 67a63aa..b562fba 100644
> --- a/security/smack/Makefile
> +++ b/security/smack/Makefile
> @@ -4,4 +4,4 @@
>
> obj-$(CONFIG_SECURITY_SMACK) := smack.o
>
> -smack-y := smack_lsm.o smack_access.o smackfs.o
> +smack-y := smack_lsm.o smack_access.o smackfs.o smack_logging.o
> diff --git a/security/smack/smack_logging.c b/security/smack/smack_logging.c
> new file mode 100644
> index 0000000..1ff81c0
> --- /dev/null
> +++ b/security/smack/smack_logging.c
> @@ -0,0 +1,460 @@
> +/*
> + * Smack logging
> + *
> + * heavily inspired by security/selinux/avc.c
> + *
> + * All credits to : Stephen Smalley, <sds(a)epoch.ncsc.mil>
> + * James Morris <jmorris(a)redhat.com>
> + * Author : Etienne Basset, <etienne.basset(a)ensta.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2,
> + * as published by the Free Software Foundation.
> + */
> +#include <linux/types.h>
> +#include <linux/stddef.h>
> +#include <linux/kernel.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <net/sock.h>
> +#include <linux/un.h>
> +#include <net/af_unix.h>
> +#include <linux/audit.h>
> +#include <linux/ipv6.h>
> +#include <linux/ip.h>
> +#include <net/ip.h>
> +#include <net/ipv6.h>
> +#include <linux/tcp.h>
> +#include <linux/udp.h>
> +#include <linux/dccp.h>
> +#include <linux/sctp.h>
> +#include "smack.h"
> +#include "smack_logging.h"
> +
> +/* what do we log
> + * can be overwrite at run-time by /smack/logging
> + */
> +struct smack_log_policy log_policy = {
> + .log_accepted = 0,
> + .log_denied = 1
> +};
> +
> +
> +
> +/**
> + * ipv4_skb_to_auditdata : fill smack_auditdata from skb
> + * @skb : the skb
> + * @ad : the audit data to fill
> + * @proto : the layer 4 protocol
> + *
> + * return 0 on success
> + */
> +int ipv4_skb_to_auditdata(struct sk_buff *skb,
> + struct smack_audit_data *ad, u8 *proto)
> +{
> + int ret = 0;
> + struct iphdr *ih;
> +
> + ih = ip_hdr(skb);
> + if (ih == NULL)
> + return -EINVAL;
> +
> + ad->u.net.v4info.saddr = ih->saddr;
> + ad->u.net.v4info.daddr = ih->daddr;
> +
> + if (proto)
> + *proto = ih->protocol;
> + /* non initial fragment */
> + if (ntohs(ih->frag_off) & IP_OFFSET)
> + return 0;
> +
> + switch (ih->protocol) {
> + case IPPROTO_TCP: {
> + struct tcphdr *th = tcp_hdr(skb);
> + if (th == NULL)
> + break;
> +
> + ad->u.net.sport = th->source;
> + ad->u.net.dport = th->dest;
> + break;
> + }
> + case IPPROTO_UDP: {
> + struct udphdr *uh = udp_hdr(skb);
> + if (uh == NULL)
> + break;
> +
> + ad->u.net.sport = uh->source;
> + ad->u.net.dport = uh->dest;
> + break;
> + }
> + case IPPROTO_DCCP: {
> + struct dccp_hdr *dh = dccp_hdr(skb);
> + if (dh == NULL)
> + break;
> +
> + ad->u.net.sport = dh->dccph_sport;
> + ad->u.net.dport = dh->dccph_dport;
> + break;
> + }
> + case IPPROTO_SCTP: {
> + struct sctphdr *sh = sctp_hdr(skb);
> + if (sh == NULL)
> + break;
> + ad->u.net.sport = sh->source;
> + ad->u.net.dport = sh->dest;
> + break;
> + }
> + default:
> + ret = -EINVAL;
> + }
> + return ret;
> +}
> +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> +/**
> + * ipv6_skb_to_auditdata : fill smack_auditdata from skb
> + * @skb : the skb
> + * @ad : the audit data to fill
> + * @proto : the layer 4 protocol
> + *
> + * return 0 on success
> + */
> +int ipv6_skb_to_auditdata(struct sk_buff *skb,
> + struct smack_audit_data *ad, u8 *proto)
> +{
> + int offset, ret = 0;
> + struct ipv6hdr *ip6;
> + u8 nexthdr;
> +
> + ip6 = ipv6_hdr(skb);
> + if (ip6 == NULL)
> + return -EINVAL;
> + ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
> + ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
> + ret = 0;
> + /* IPv6 can have several extension header before the Transport header
> + * skip them */
> + offset = skb_network_offset(skb);
> + offset += sizeof(*ip6);
> + nexthdr = ip6->nexthdr;
> + offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
> + if (offset < 0)
> + return 0;
> + if (proto)
> + *proto = nexthdr;
> + switch (nexthdr) {
> + case IPPROTO_TCP: {
> + struct tcphdr _tcph, *th;
> +
> + th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
> + if (th == NULL)
> + break;
> +
> + ad->u.net.sport = th->source;
> + ad->u.net.dport = th->dest;
> + break;
> + }
> + case IPPROTO_UDP: {
> + struct udphdr _udph, *uh;
> +
> + uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
> + if (uh == NULL)
> + break;
> +
> + ad->u.net.sport = uh->source;
> + ad->u.net.dport = uh->dest;
> + break;
> + }
> + case IPPROTO_DCCP: {
> + struct dccp_hdr _dccph, *dh;
> +
> + dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
> + if (dh == NULL)
> + break;
> +
> + ad->u.net.sport = dh->dccph_sport;
> + ad->u.net.dport = dh->dccph_dport;
> + break;
> + }
> + case IPPROTO_SCTP: {
> + struct sctphdr _sctph, *sh;
> +
> + sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
> + if (sh == NULL)
> + break;
> + ad->u.net.sport = sh->source;
> + ad->u.net.dport = sh->dest;
> + break;
> + }
> + default:
> + ret = -EINVAL;
> + }
> + return ret;
> +}
> +#endif
> +
> +
> +static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
> + struct in6_addr *addr, __be16 port,
> + char *name1, char *name2)
> +{
> + if (!ipv6_addr_any(addr))
> + audit_log_format(ab, " %s=%pI6", name1, addr);
> + if (port)
> + audit_log_format(ab, " %s=%d", name2, ntohs(port));
> +}
> +
> +static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
> + __be16 port, char *name1, char *name2)
> +{
> + if (addr)
> + audit_log_format(ab, " %s=%pI4", name1, &addr);
> + if (port)
> + audit_log_format(ab, " %s=%d", name2, ntohs(port));
> +}
> +/**
> + * smack_str_from_perm : helper to transalate an int to a
> + * readable string
> + * @string : the string to fill
> + * @access : the int
> + *
> + */
> +static inline void smack_str_from_perm(char *string, int access)
> +{
> + int i = 0;
> + if (access & MAY_READ)
> + string[i++] = 'r';
> + if (access & MAY_WRITE)
> + string[i++] = 'w';
> + if (access & MAY_EXEC)
> + string[i++] = 'x';
> + if (access & MAY_APPEND)
> + string[i++] = 'a';
> + string[i] = '\0';
> +}
> +
> +
> +/**
> + * smack_log - Audit the granting or denial of permissions.
> + * @subject_label : smack label of the requester
> + * @object_label : smack label of the object being accessed
> + * @request: requested permissions
> + * @result: result from smk_access
> + * @a: auxiliary audit data
> + *
> + * Audit the granting or denial of permissions in accordance
> + * with the policy.
> + */
> +void smack_log(char *subject_label, char *object_label, int request,
> + int result, struct smack_audit_data *a)
> +{
> + struct task_struct *tsk = current;
> + struct inode *inode = NULL;
> + struct audit_buffer *ab;
> + char request_buffer[5];
> + u32 denied;
> + u32 audited = 0;
> +
> + /* check if we have to log the current event */
> + if (result != 0) {
> + denied = 1;
> + if (log_policy.log_denied)
> + audited = 1;
> + } else {
> + denied = 0;
> + if (log_policy.log_accepted)
> + audited = 1;
> + }
> + if (audited == 0)
> + return;
> +
> + /* we use GFP_ATOMIC so we won't sleep */
> + ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
> + if (!ab)
> + return;
> + audit_log_format(ab, "SMACK[%s]: %s ", a->function, denied ? "denied" : "granted");
> +
> + if (a && a->tsk)
> + tsk = a->tsk;
> + if (tsk && tsk->pid) {
> + audit_log_format(ab, " pid=%d comm=", tsk->pid);
> + audit_log_untrustedstring(ab, tsk->comm);
> + }
> + smack_str_from_perm(request_buffer, request);
> + audit_log_format(ab, " subject:'%s' object:'%s' requested:%s ",
> + subject_label, object_label, request_buffer);
> +
> + if (a==NULL)
> + goto audit_log_end;
> +
> + switch (a->type) {
> + case AVC_AUDIT_DATA_IPC:
> + audit_log_format(ab, "key=%d ", a->u.ipc_id);
> + break;
> + case AVC_AUDIT_DATA_CAP:
> + audit_log_format(ab, "capability=%d ", a->u.cap);
> + break;
> + case AVC_AUDIT_DATA_FS:
> + if (a->u.fs.path.dentry) {
> + struct dentry *dentry = a->u.fs.path.dentry;
> + if (a->u.fs.path.mnt) {
> + audit_log_d_path(ab, "path=", &a->u.fs.path);
> + } else {
> + audit_log_format(ab, "name=");
> + audit_log_untrustedstring(ab, dentry->d_name.name);
> + }
> + inode = dentry->d_inode;
> + } else if (a->u.fs.inode) {
> + struct dentry *dentry;
> + inode = a->u.fs.inode;
> + dentry = d_find_alias(inode);
> + if (dentry) {
> + audit_log_format(ab, "name=");
> + audit_log_untrustedstring(ab, dentry->d_name.name);
> + dput(dentry);
> + }
> + }
> + if (inode)
> + audit_log_format(ab, " dev=%s ino=%lu",
> + inode->i_sb->s_id,
> + inode->i_ino);
> + break;
> + case AVC_AUDIT_DATA_TASK:
> + tsk = a->u.tsk;
> + if (tsk && tsk->pid) {
> + audit_log_format(ab, "pid=%d comm=", tsk->pid);
> + audit_log_untrustedstring(ab, tsk->comm);
> + }
> + break;
> + case AVC_AUDIT_DATA_NET:
> + if (a->u.net.sk) {
> + struct sock *sk = a->u.net.sk;
> + struct unix_sock *u;
> + int len = 0;
> + char *p = NULL;
> +
> + switch (sk->sk_family) {
> + case AF_INET: {
> + struct inet_sock *inet = inet_sk(sk);
> +
> + avc_print_ipv4_addr(ab, inet->rcv_saddr,
> + inet->sport,
> + "laddr", "lport");
> + avc_print_ipv4_addr(ab, inet->daddr,
> + inet->dport,
> + "faddr", "fport");
> + break;
> + }
> + case AF_INET6: {
> + struct inet_sock *inet = inet_sk(sk);
> + struct ipv6_pinfo *inet6 = inet6_sk(sk);
> +
> + avc_print_ipv6_addr(ab, &inet6->rcv_saddr,
> + inet->sport,
> + "laddr", "lport");
> + avc_print_ipv6_addr(ab, &inet6->daddr,
> + inet->dport,
> + "faddr", "fport");
> + break;
> + }
> + case AF_UNIX:
> + u = unix_sk(sk);
> + if (u->dentry) {
> + struct path path = {
> + .dentry = u->dentry,
> + .mnt = u->mnt
> + };
> + audit_log_d_path(ab, "path=",
> + &path);
> + break;
> + }
> + if (!u->addr)
> + break;
> + len = u->addr->len-sizeof(short);
> + p = &u->addr->name->sun_path[0];
> + audit_log_format(ab, " path=");
> + if (*p)
> + audit_log_untrustedstring(ab, p);
> + else
> + audit_log_n_hex(ab, p, len);
> + break;
> + }
> + }
> +
> + switch (a->u.net.family) {
> + case AF_INET:
> + avc_print_ipv4_addr(ab, a->u.net.v4info.saddr,
> + a->u.net.sport,
> + "saddr", ":");
> + avc_print_ipv4_addr(ab, a->u.net.v4info.daddr,
> + a->u.net.dport,
> + "daddr", ":");
> + break;
> + case AF_INET6:
> + avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr,
> + a->u.net.sport,
> + "saddr", ":");
> + avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr,
> + a->u.net.dport,
> + "daddr", ":");
> + break;
> + }
> + if (a->u.net.netif > 0) {
> + struct net_device *dev;
> +
> + /* NOTE: we always use init's namespace */
> + dev = dev_get_by_index(&init_net,
> + a->u.net.netif);
> + if (dev) {
> + audit_log_format(ab, " netif=%s",
> + dev->name);
> + dev_put(dev);
> + }
> + }
> + break;
> +#ifdef CONFIG_KEYS
> + case AVC_AUDIT_DATA_KEY:
> + audit_log_format(ab, " key serial=%u", a->u.key);
> + if (a->u.key_desc)
> + audit_log_format(ab, " key desc=%s", a->u.key_desc);
> + break;
> +#endif
> + } /* switch (a->type) */
> +
> +audit_log_end:
> + audit_log_end(ab);
> +}
> +
> +/**
> + * smk_curracc_log : check access of current on olabel
> + * @olabel : label being accessed
> + * @access : access requested
> + * @a : pointer to data
> + *
> + * return the same perm return by smk_curacc
> + */
> +int smk_curacc_log(char *olabel, int access, struct smack_audit_data *a)
> +{
> + int rc;
> + rc = smk_curacc(olabel, access);
> + smack_log(current_security(), olabel, access, rc, a);
> + return rc;
> +}
> +
> +/**
> + * smk_access_log : check access of slabel on olabel
> + * @slabel : subjet label
> + * @olabel : label being accessed
> + * @access : access requested
> + * @a : pointer to data
> + *
> + * return the same perm return by smk_access
> + */
> +int smk_access_log(char *slabel, char *olabel, int access,
> + struct smack_audit_data *a)
> +{
> + int rc;
> + rc = smk_access(slabel, olabel, access);
> + smack_log(slabel, olabel, access, rc, a);
> + return rc;
> +}
> +
> diff --git a/security/smack/smack_logging.h b/security/smack/smack_logging.h
> new file mode 100644
> index 0000000..1a01574
> --- /dev/null
> +++ b/security/smack/smack_logging.h
> @@ -0,0 +1,97 @@
> +/*
> + * Smack logging function
> + * Heavily borrowed from selinux/avc.h
> + *
> + * Author : Etienne BASSET <etienne.basset(a)ensta.org>
> + *
> + * All credits to : Stephen Smalley, <sds(a)epoch.ncsc.mil>
> + * All BUGS to : Etienne BASSET <etienne.basset(a)ensta.org>
> + */
> +#ifndef _SMACK_LOGGING_
> +#define _SMACK_LOGGING_
> +
> +#include <linux/stddef.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/kdev_t.h>
> +#include <linux/spinlock.h>
> +#include <linux/init.h>
> +#include <linux/audit.h>
> +#include <linux/in6.h>
> +#include <linux/path.h>
> +#include <asm/system.h>
> +#include <linux/key.h>
> +
> +
> +struct smack_log_policy {
> + int log_accepted;
> + int log_denied;
> +};
> +extern struct smack_log_policy log_policy;
> +
> +
> +/* Auxiliary data to use in generating the audit record. */
> +struct smack_audit_data {
> + char type;
> +#define AVC_AUDIT_DATA_FS 1
> +#define AVC_AUDIT_DATA_NET 2
> +#define AVC_AUDIT_DATA_CAP 3
> +#define AVC_AUDIT_DATA_IPC 4
> +#define AVC_AUDIT_DATA_TASK 5
> +#define AVC_AUDIT_DATA_KEY 6
> + struct task_struct *tsk;
> + union {
> + struct {
> + struct path path;
> + struct inode *inode;
> + } fs;
> + struct {
> + int netif;
> + struct sock *sk;
> + u16 family;
> + __be16 dport;
> + __be16 sport;
> + union {
> + struct {
> + __be32 daddr;
> + __be32 saddr;
> + } v4;
> + struct {
> + struct in6_addr daddr;
> + struct in6_addr saddr;
> + } v6;
> + } fam;
> + } net;
> + int cap;
> + int ipc_id;
> + struct task_struct *tsk;
> +#ifdef CONFIG_KEYS
> + key_serial_t key;
> + char *key_desc;
> +#endif
> + } u;
> + const char *function;
> +};
> +
> +#define v4info fam.v4
> +#define v6info fam.v6
> +
> +int ipv4_skb_to_auditdata(struct sk_buff *skb,
> + struct smack_audit_data *ad, u8 *proto);
> +
> +int ipv6_skb_to_auditdata(struct sk_buff *skb,
> + struct smack_audit_data *ad, u8 *proto);
> +
> +/* Initialize an AVC audit data structure. */
> +#define SMACK_AUDIT_DATA_INIT(_d, _t) \
> + { memset((_d), 0, sizeof(struct smack_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; (_d)->function = __func__; }
> +
> +void smack_log(char *subject_label, char *object_label,
> + int request,
> + int result, struct smack_audit_data *auditdata);
> +
> +int smk_access_log(char *subjectlabel, char *olabel, int access,
> + struct smack_audit_data *a);
> +int smk_curacc_log(char *olabel, int access, struct smack_audit_data *a);
> +
> +#endif
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 0278bc0..6e7af4e 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -29,6 +29,7 @@
> #include <linux/audit.h>
>
> #include "smack.h"
> +#include "smack_logging.h"
>
> #define task_security(task) (task_cred_xxx((task), security))
>
> @@ -99,14 +100,20 @@ struct inode_smack *new_inode_smack(char *smack)
> static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
> {
> int rc;
> + struct smack_audit_data ad;
>
> rc = cap_ptrace_may_access(ctp, mode);
> if (rc != 0)
> return rc;
>
> + SMACK_AUDIT_DATA_INIT(&ad, TASK);
> + ad.u.tsk = ctp;
> + /* we won't log here, because rc can be overriden */
> rc = smk_access(current_security(), task_security(ctp), MAY_READWRITE);
> if (rc != 0 && capable(CAP_MAC_OVERRIDE))
> - return 0;
> + rc = 0;
> +
> + smack_log(current_security(), task_security(ctp), MAY_READWRITE, rc, &ad);
> return rc;
> }
>
> @@ -121,14 +128,20 @@ static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
> static int smack_ptrace_traceme(struct task_struct *ptp)
> {
> int rc;
> -
> + struct smack_audit_data ad;
> rc = cap_ptrace_traceme(ptp);
> if (rc != 0)
> return rc;
>
> + SMACK_AUDIT_DATA_INIT(&ad, TASK);
> + ad.u.tsk = ptp;
> +
> + /* we won't log here, because rc can be overriden */
> rc = smk_access(task_security(ptp), current_security(), MAY_READWRITE);
> if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
> - return 0;
> + rc = 0;
> +
> + smack_log(task_security(ptp), current_security(), MAY_READWRITE, rc, &ad);
> return rc;
> }
>
> @@ -324,8 +337,14 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
> static int smack_sb_statfs(struct dentry *dentry)
> {
> struct superblock_smack *sbp = dentry->d_sb->s_security;
> + struct smack_audit_data ad;
> + int rc;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
>
> - return smk_curacc(sbp->smk_floor, MAY_READ);
> + rc = smk_curacc_log(sbp->smk_floor, MAY_READ, &ad);
> + return rc;
> }
>
> /**
> @@ -343,8 +362,12 @@ static int smack_sb_mount(char *dev_name, struct path *path,
> char *type, unsigned long flags, void *data)
> {
> struct superblock_smack *sbp = path->mnt->mnt_sb->s_security;
> + struct smack_audit_data ad;
>
> - return smk_curacc(sbp->smk_floor, MAY_WRITE);
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = path->dentry;
> + ad.u.fs.path.mnt = path->mnt;
> + return smk_curacc_log(sbp->smk_floor, MAY_WRITE, &ad);
> }
>
> /**
> @@ -358,10 +381,14 @@ static int smack_sb_mount(char *dev_name, struct path *path,
> static int smack_sb_umount(struct vfsmount *mnt, int flags)
> {
> struct superblock_smack *sbp;
> + struct smack_audit_data ad;
>
> sbp = mnt->mnt_sb->s_security;
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = mnt->mnt_mountpoint;
> + ad.u.fs.path.mnt = mnt;
>
> - return smk_curacc(sbp->smk_floor, MAY_WRITE);
> + return smk_curacc_log(sbp->smk_floor, MAY_WRITE, &ad);
> }
>
> /*
> @@ -438,15 +465,20 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
> static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
> struct dentry *new_dentry)
> {
> - int rc;
> char *isp;
> + struct smack_audit_data ad;
> + int rc;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = old_dentry;
>
> isp = smk_of_inode(old_dentry->d_inode);
> - rc = smk_curacc(isp, MAY_WRITE);
> + rc = smk_curacc_log(isp, MAY_WRITE, &ad);
>
> if (rc == 0 && new_dentry->d_inode != NULL) {
> isp = smk_of_inode(new_dentry->d_inode);
> - rc = smk_curacc(isp, MAY_WRITE);
> + ad.u.fs.path.dentry = new_dentry;
> + rc = smk_curacc_log(isp, MAY_WRITE, &ad);
> }
>
> return rc;
> @@ -463,18 +495,24 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
> static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
> {
> struct inode *ip = dentry->d_inode;
> + struct smack_audit_data ad;
> int rc;
>
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
> +
> /*
> * You need write access to the thing you're unlinking
> */
> - rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
> - if (rc == 0)
> + rc = smk_curacc_log(smk_of_inode(ip), MAY_WRITE, &ad);
> + if (rc == 0) {
> /*
> * You also need write access to the containing directory
> */
> - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
> -
> + ad.u.fs.path.dentry = NULL;
> + ad.u.fs.inode = dir;
> + rc = smk_curacc_log(smk_of_inode(dir), MAY_WRITE, &ad);
> + }
> return rc;
> }
>
> @@ -488,17 +526,24 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
> */
> static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
> {
> + struct smack_audit_data ad;
> int rc;
>
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
> +
> /*
> * You need write access to the thing you're removing
> */
> - rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
> - if (rc == 0)
> + rc = smk_curacc_log(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
> + if (rc == 0) {
> /*
> * You also need write access to the containing directory
> */
> - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
> + ad.u.fs.path.dentry = NULL;
> + ad.u.fs.inode = dir;
> + rc = smk_curacc_log(smk_of_inode(dir), MAY_WRITE, &ad);
> + }
>
> return rc;
> }
> @@ -522,15 +567,19 @@ static int smack_inode_rename(struct inode *old_inode,
> {
> int rc;
> char *isp;
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = old_dentry;
>
> isp = smk_of_inode(old_dentry->d_inode);
> - rc = smk_curacc(isp, MAY_READWRITE);
> + rc = smk_curacc_log(isp, MAY_READWRITE, &ad);
>
> if (rc == 0 && new_dentry->d_inode != NULL) {
> isp = smk_of_inode(new_dentry->d_inode);
> - rc = smk_curacc(isp, MAY_READWRITE);
> + ad.u.fs.path.dentry = new_dentry;
> + rc = smk_curacc_log(isp, MAY_READWRITE, &ad);
> }
> -
> return rc;
> }
>
> @@ -546,14 +595,16 @@ static int smack_inode_rename(struct inode *old_inode,
> */
> static int smack_inode_permission(struct inode *inode, int mask)
> {
> + struct smack_audit_data ad;
> /*
> * No permission to check. Existence test. Yup, it's there.
> */
> if (mask == 0)
> return 0;
> -
> - return smk_curacc(smk_of_inode(inode), mask);
> -}
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.inode = inode;
> + return smk_curacc_log(smk_of_inode(inode), mask, &ad);
> + }
>
> /**
> * smack_inode_setattr - Smack check for setting attributes
> @@ -564,13 +615,15 @@ static int smack_inode_permission(struct inode *inode, int mask)
> */
> static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
> {
> + struct smack_audit_data ad;
> /*
> * Need to allow for clearing the setuid bit.
> */
> if (iattr->ia_valid & ATTR_FORCE)
> return 0;
> -
> - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
> + return smk_curacc_log(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
> }
>
> /**
> @@ -582,7 +635,12 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
> */
> static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
> {
> - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
> + ad.u.fs.path.mnt = mnt;
> + return smk_curacc_log(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
> }
>
> /**
> @@ -600,6 +658,7 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
> static int smack_inode_setxattr(struct dentry *dentry, const char *name,
> const void *value, size_t size, int flags)
> {
> + struct smack_audit_data ad;
> int rc = 0;
>
> if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
> @@ -610,8 +669,10 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
> } else
> rc = cap_inode_setxattr(dentry, name, value, size, flags);
>
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
> if (rc == 0)
> - rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
> + rc = smk_curacc_log(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
>
> return rc;
> }
> @@ -666,7 +727,11 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
> */
> static int smack_inode_getxattr(struct dentry *dentry, const char *name)
> {
> - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
> + return smk_curacc_log(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
> }
>
> /*
> @@ -680,6 +745,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
> */
> static int smack_inode_removexattr(struct dentry *dentry, const char *name)
> {
> + struct smack_audit_data ad;
> int rc = 0;
>
> if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
> @@ -690,8 +756,10 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
> } else
> rc = cap_inode_removexattr(dentry, name);
>
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = dentry;
> if (rc == 0)
> - rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
> + rc = smk_curacc_log(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
>
> return rc;
> }
> @@ -851,12 +919,16 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
> unsigned long arg)
> {
> int rc = 0;
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path = file->f_path;
>
> if (_IOC_DIR(cmd) & _IOC_WRITE)
> - rc = smk_curacc(file->f_security, MAY_WRITE);
> + rc = smk_curacc_log(file->f_security, MAY_WRITE, &ad);
>
> if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
> - rc = smk_curacc(file->f_security, MAY_READ);
> + rc = smk_curacc_log(file->f_security, MAY_READ, &ad);
>
> return rc;
> }
> @@ -870,7 +942,11 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
> */
> static int smack_file_lock(struct file *file, unsigned int cmd)
> {
> - return smk_curacc(file->f_security, MAY_WRITE);
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path.dentry = file->f_path.dentry;
> + return smk_curacc_log(file->f_security, MAY_WRITE, &ad);
> }
>
> /**
> @@ -884,8 +960,12 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
> static int smack_file_fcntl(struct file *file, unsigned int cmd,
> unsigned long arg)
> {
> + struct smack_audit_data ad;
> int rc;
>
> + SMACK_AUDIT_DATA_INIT(&ad, FS);
> + ad.u.fs.path = file->f_path;
> +
> switch (cmd) {
> case F_DUPFD:
> case F_GETFD:
> @@ -893,7 +973,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
> case F_GETLK:
> case F_GETOWN:
> case F_GETSIG:
> - rc = smk_curacc(file->f_security, MAY_READ);
> + rc = smk_curacc_log(file->f_security, MAY_READ, &ad);
> break;
> case F_SETFD:
> case F_SETFL:
> @@ -901,10 +981,10 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
> case F_SETLKW:
> case F_SETOWN:
> case F_SETSIG:
> - rc = smk_curacc(file->f_security, MAY_WRITE);
> + rc = smk_curacc_log(file->f_security, MAY_WRITE, &ad);
> break;
> default:
> - rc = smk_curacc(file->f_security, MAY_READWRITE);
> + rc = smk_curacc_log(file->f_security, MAY_READWRITE, &ad);
> }
>
> return rc;
> @@ -939,14 +1019,20 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
> {
> struct file *file;
> int rc;
> + struct smack_audit_data ad;
>
> /*
> * struct fown_struct is never outside the context of a struct file
> */
> file = container_of(fown, struct file, f_owner);
> + /* we don't log here as rc can be overriden */
> rc = smk_access(file->f_security, tsk->cred->security, MAY_WRITE);
> if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
> return 0;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, TASK);
> + ad.u.tsk = tsk;
> + smack_log(file->f_security, tsk->cred->security, MAY_WRITE, rc, &ad);
> return rc;
> }
>
> @@ -959,7 +1045,10 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
> static int smack_file_receive(struct file *file)
> {
> int may = 0;
> + struct smack_audit_data ad;
>
> + SMACK_AUDIT_DATA_INIT(&ad, TASK);
> + ad.u.fs.path = file->f_path;
> /*
> * This code relies on bitmasks.
> */
> @@ -968,7 +1057,7 @@ static int smack_file_receive(struct file *file)
> if (file->f_mode & FMODE_WRITE)
> may |= MAY_WRITE;
>
> - return smk_curacc(file->f_security, may);
> + return smk_curacc_log(file->f_security, may, &ad);
> }
>
> /*
> @@ -1048,6 +1137,22 @@ static int smack_kernel_create_files_as(struct cred *new,
> }
>
> /**
> + * smk_curacc_on_task - helper to log task related access
> + * @p: the task object
> + * @access : the access requested
> + *
> + * Return 0 if access is permitted
> + */
> +static int smk_curacc_on_task(struct task_struct *p, int access)
> +{
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, TASK);
> + ad.u.tsk = p;
> + return smk_curacc_log(task_security(p), access, &ad);
> +}
> +
> +/**
> * smack_task_setpgid - Smack check on setting pgid
> * @p: the task object
> * @pgid: unused
> @@ -1056,7 +1161,7 @@ static int smack_kernel_create_files_as(struct cred *new,
> */
> static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
> {
> - return smk_curacc(task_security(p), MAY_WRITE);
> + return smk_curacc_on_task(p, MAY_WRITE);
> }
>
> /**
> @@ -1067,7 +1172,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
> */
> static int smack_task_getpgid(struct task_struct *p)
> {
> - return smk_curacc(task_security(p), MAY_READ);
> + return smk_curacc_on_task(p, MAY_READ);
> }
>
> /**
> @@ -1078,7 +1183,7 @@ static int smack_task_getpgid(struct task_struct *p)
> */
> static int smack_task_getsid(struct task_struct *p)
> {
> - return smk_curacc(task_security(p), MAY_READ);
> + return smk_curacc_on_task(p, MAY_READ);
> }
>
> /**
> @@ -1106,7 +1211,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)
>
> rc = cap_task_setnice(p, nice);
> if (rc == 0)
> - rc = smk_curacc(task_security(p), MAY_WRITE);
> + rc = smk_curacc_on_task(p, MAY_WRITE);
> return rc;
> }
>
> @@ -1123,7 +1228,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
>
> rc = cap_task_setioprio(p, ioprio);
> if (rc == 0)
> - rc = smk_curacc(task_security(p), MAY_WRITE);
> + rc = smk_curacc_on_task(p, MAY_WRITE);
> return rc;
> }
>
> @@ -1135,7 +1240,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
> */
> static int smack_task_getioprio(struct task_struct *p)
> {
> - return smk_curacc(task_security(p), MAY_READ);
> + return smk_curacc_on_task(p, MAY_READ);
> }
>
> /**
> @@ -1153,7 +1258,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
>
> rc = cap_task_setscheduler(p, policy, lp);
> if (rc == 0)
> - rc = smk_curacc(task_security(p), MAY_WRITE);
> + rc = smk_curacc_on_task(p, MAY_WRITE);
> return rc;
> }
>
> @@ -1165,7 +1270,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
> */
> static int smack_task_getscheduler(struct task_struct *p)
> {
> - return smk_curacc(task_security(p), MAY_READ);
> + return smk_curacc_on_task(p, MAY_READ);
> }
>
> /**
> @@ -1176,7 +1281,7 @@ static int smack_task_getscheduler(struct task_struct *p)
> */
> static int smack_task_movememory(struct task_struct *p)
> {
> - return smk_curacc(task_security(p), MAY_WRITE);
> + return smk_curacc_on_task(p, MAY_WRITE);
> }
>
> /**
> @@ -1194,18 +1299,23 @@ static int smack_task_movememory(struct task_struct *p)
> static int smack_task_kill(struct task_struct *p, struct siginfo *info,
> int sig, u32 secid)
> {
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, TASK);
> + ad.u.tsk = p;
> /*
> * Sending a signal requires that the sender
> * can write the receiver.
> */
> if (secid == 0)
> - return smk_curacc(task_security(p), MAY_WRITE);
> + return smk_curacc_log(task_security(p), MAY_WRITE, &ad);
> /*
> * If the secid isn't 0 we're dealing with some USB IO
> * specific behavior. This is not clean. For one thing
> * we can't take privilege into account.
> */
> - return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE);
> + return smk_access_log(smack_from_secid(secid), task_security(p),
> + MAY_WRITE, &ad);
> }
>
> /**
> @@ -1216,12 +1326,13 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
> */
> static int smack_task_wait(struct task_struct *p)
> {
> + struct smack_audit_data ad;
> int rc;
>
> + /* we don't log here, we can be overriden */
> rc = smk_access(current_security(), task_security(p), MAY_WRITE);
> if (rc == 0)
> - return 0;
> -
> + goto out_log;
> /*
> * Allow the operation to succeed if either task
> * has privilege to perform operations that might
> @@ -1235,7 +1346,11 @@ static int smack_task_wait(struct task_struct *p)
> */
> if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE))
> return 0;
> -
> + /* we log only if we didn't get overriden */
> + out_log:
> + SMACK_AUDIT_DATA_INIT(&ad, TASK);
> + ad.u.tsk = p;
> + smack_log(current_security(), task_security(p), MAY_WRITE, rc, &ad);
> return rc;
> }
>
> @@ -1567,22 +1682,30 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
> {
> struct socket_smack *ssp = sock->sk->sk_security;
> char *hostsp;
> + struct smack_audit_data ad;
> + struct sockaddr_in *sin;
> int rc;
>
> +
> if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
> return 0;
>
> if (addrlen < sizeof(struct sockaddr_in))
> return -EINVAL;
> -
> - hostsp = smack_host_label((struct sockaddr_in *)sap);
> + sin = (struct sockaddr_in *)sap;
> + hostsp = smack_host_label(sin);
> if (hostsp == NULL) {
> if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
> return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
> return 0;
> }
> + SMACK_AUDIT_DATA_INIT(&ad, NET);
> + ad.u.net.family = sock->sk->sk_family;
> + ad.u.net.v4info.daddr = sin->sin_addr.s_addr;
> + ad.u.net.dport = sin->sin_port;
> +
> + rc = smk_access_log(ssp->smk_out, hostsp, MAY_WRITE, &ad);
>
> - rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
> if (rc != 0)
> return rc;
>
> @@ -1673,6 +1796,23 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
> }
>
> /**
> + * smk_curacc_shm : check if current has access on shm
> + * @shp : the object
> + * @access : access requested
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smk_curacc_shm(struct shmid_kernel *shp, int access)
> +{
> + char *ssp = smack_of_shm(shp);
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, IPC);
> + ad.u.ipc_id = shp->shm_perm.id;
> + return smk_curacc_log(ssp, access, &ad);
> +}
> +
> +/**
> * smack_shm_associate - Smack access check for shm
> * @shp: the object
> * @shmflg: access requested
> @@ -1681,11 +1821,10 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
> */
> static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
> {
> - char *ssp = smack_of_shm(shp);
> int may;
>
> may = smack_flags_to_may(shmflg);
> - return smk_curacc(ssp, may);
> + return smk_curacc_shm(shp, may);
> }
>
> /**
> @@ -1697,7 +1836,6 @@ static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
> */
> static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
> {
> - char *ssp;
> int may;
>
> switch (cmd) {
> @@ -1720,9 +1858,7 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
> default:
> return -EINVAL;
> }
> -
> - ssp = smack_of_shm(shp);
> - return smk_curacc(ssp, may);
> + return smk_curacc_shm(shp, may);
> }
>
> /**
> @@ -1736,11 +1872,10 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
> static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
> int shmflg)
> {
> - char *ssp = smack_of_shm(shp);
> int may;
>
> may = smack_flags_to_may(shmflg);
> - return smk_curacc(ssp, may);
> + return smk_curacc_shm(shp, may);
> }
>
> /**
> @@ -1782,6 +1917,23 @@ static void smack_sem_free_security(struct sem_array *sma)
> }
>
> /**
> + * smk_curacc_sem : check if current has access on sem
> + * @sma : the object
> + * @access : access requested
> + *
> + * Returns 0 if current has the requested access, error code otherwise
> + */
> +static int smk_curacc_sem(struct sem_array *sma, int access)
> +{
> + char *ssp = smack_of_sem(sma);
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, IPC);
> + ad.u.ipc_id = sma->sem_perm.id;
> + return smk_curacc_log(ssp, access, &ad);
> +}
> +
> +/**
> * smack_sem_associate - Smack access check for sem
> * @sma: the object
> * @semflg: access requested
> @@ -1790,11 +1942,10 @@ static void smack_sem_free_security(struct sem_array *sma)
> */
> static int smack_sem_associate(struct sem_array *sma, int semflg)
> {
> - char *ssp = smack_of_sem(sma);
> int may;
>
> may = smack_flags_to_may(semflg);
> - return smk_curacc(ssp, may);
> + return smk_curacc_sem(sma, may);
> }
>
> /**
> @@ -1806,7 +1957,6 @@ static int smack_sem_associate(struct sem_array *sma, int semflg)
> */
> static int smack_sem_semctl(struct sem_array *sma, int cmd)
> {
> - char *ssp;
> int may;
>
> switch (cmd) {
> @@ -1835,8 +1985,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd)
> return -EINVAL;
> }
>
> - ssp = smack_of_sem(sma);
> - return smk_curacc(ssp, may);
> + return smk_curacc_sem(sma, may);
> }
>
> /**
> @@ -1853,9 +2002,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd)
> static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
> unsigned nsops, int alter)
> {
> - char *ssp = smack_of_sem(sma);
> -
> - return smk_curacc(ssp, MAY_READWRITE);
> + return smk_curacc_sem(sma, MAY_READWRITE);
> }
>
> /**
> @@ -1897,6 +2044,23 @@ static char *smack_of_msq(struct msg_queue *msq)
> }
>
> /**
> + * smk_curacc_msq : helper to check if current has access on msq
> + * @msq : the msq
> + * @access : access requested
> + *
> + * return 0 if current has access, error otherwise
> + */
> +static int smk_curacc_msq(struct msg_queue *msq, int access)
> +{
> + char *msp = smack_of_msq(msq);
> + struct smack_audit_data ad;
> +
> + SMACK_AUDIT_DATA_INIT(&ad, IPC);
> + ad.u.ipc_id = msq->q_perm.id;
> + return smk_curacc_log(msp, access, &ad);
> +}
> +
> +/**
> * smack_msg_queue_associate - Smack access check for msg_queue
> * @msq: the object
> * @msqflg: access requested
> @@ -1905,11 +2069,10 @@ static char *smack_of_msq(struct msg_queue *msq)
> */
> static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
> {
> - char *msp = smack_of_msq(msq);
> int may;
>
> may = smack_flags_to_may(msqflg);
> - return smk_curacc(msp, may);
> + return smk_curacc_msq(msq, may);
> }
>
> /**
> @@ -1921,7 +2084,6 @@ static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
> */
> static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
> {
> - char *msp;
> int may;
>
> switch (cmd) {
> @@ -1943,8 +2105,7 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
> return -EINVAL;
> }
>
> - msp = smack_of_msq(msq);
> - return smk_curacc(msp, may);
> + return smk_curacc_msq(msq, may);
> }
>
> /**
> @@ -1958,11 +2119,10 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
> static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
> int msqflg)
> {
> - char *msp = smack_of_msq(msq);
> - int rc;
> + int may;
>
> - rc = smack_flags_to_may(msqflg);
> - return smk_curacc(msp, rc);
> + may = smack_flags_to_may(msqflg);
> + return smk_curacc_msq(msq, may);
> }
>
> /**
> @@ -1978,9 +2138,7 @@ static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
> static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
> struct task_struct *target, long type, int mode)
> {
> - char *msp = smack_of_msq(msq);
> -
> - return smk_curacc(msp, MAY_READWRITE);
> + return smk_curacc_msq(msq, MAY_READWRITE);
> }
>
> /**
> @@ -1993,10 +2151,13 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
> static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
> {
> char *isp = ipp->security;
> + struct smack_audit_data ad;
> int may;
> + SMACK_AUDIT_DATA_INIT(&ad, IPC);
> + ad.u.ipc_id = ipp->id;
>
> may = smack_flags_to_may(flag);
> - return smk_curacc(isp, may);
> + return smk_curacc_log(isp, may, &ad);
> }
>
> /**
> @@ -2255,8 +2416,12 @@ static int smack_unix_stream_connect(struct socket *sock,
> {
> struct inode *sp = SOCK_INODE(sock);
> struct inode *op = SOCK_INODE(other);
> + struct smack_audit_data ad;
>
> - return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE);
> + SMACK_AUDIT_DATA_INIT(&ad, NET);
> + ad.u.net.sk = other->sk;
> + return smk_access_log(smk_of_inode(sp), smk_of_inode(op),
> + MAY_READWRITE, &ad);
> }
>
> /**
> @@ -2271,8 +2436,12 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
> {
> struct inode *sp = SOCK_INODE(sock);
> struct inode *op = SOCK_INODE(other);
> + struct smack_audit_data ad;
>
> - return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
> + SMACK_AUDIT_DATA_INIT(&ad, NET);
> + ad.u.net.sk = other->sk;
> + return smk_access_log(smk_of_inode(sp), smk_of_inode(op),
> + MAY_WRITE, &ad);
> }
>
> /**
> @@ -2292,6 +2461,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
> struct socket_smack *ssp = sock->sk->sk_security;
> char *hostsp;
> int rc;
> + struct smack_audit_data ad;
>
> /*
> * Perfectly reasonable for this to be NULL
> @@ -2305,8 +2475,12 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
> return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
> return 0;
> }
> + SMACK_AUDIT_DATA_INIT(&ad, NET);
> + ad.u.net.family = sip->sin_family;
> + ad.u.net.dport = sip->sin_port;
> + ad.u.net.v4info.daddr = sip->sin_addr.s_addr;
>
> - rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
> + rc = smk_access_log(ssp->smk_out, hostsp, MAY_WRITE, &ad);
> if (rc != 0)
> return rc;
>
> @@ -2314,7 +2488,6 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
> return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
>
> return 0;
> -
> }
>
>
> @@ -2405,6 +2578,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
> struct socket_smack *ssp = sk->sk_security;
> char smack[SMK_LABELLEN];
> char *csp;
> + struct smack_audit_data ad;
> int rc;
>
> if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
> @@ -2424,13 +2598,17 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>
> netlbl_secattr_destroy(&secattr);
>
> + SMACK_AUDIT_DATA_INIT(&ad, NET);
> + ad.u.net.family = sk->sk_family;
> + ad.u.net.netif = skb->iif;
> + ipv4_skb_to_auditdata(skb, &ad, NULL);
> /*
> * Receiving a packet requires that the other end
> * be able to write here. Read access is not required.
> * This is the simplist possible security model
> * for networking.
> */
> - rc = smk_access(csp, ssp->smk_in, MAY_WRITE);
> + rc = smk_access_log(csp, ssp->smk_in, MAY_WRITE, &ad);
> if (rc != 0)
> netlbl_skbuff_err(skb, rc, 0);
> return rc;
> @@ -2638,6 +2816,7 @@ static int smack_key_permission(key_ref_t key_ref,
> const struct cred *cred, key_perm_t perm)
> {
> struct key *keyp;
> + struct smack_audit_data ad;
>
> keyp = key_ref_to_ptr(key_ref);
> if (keyp == NULL)
> @@ -2653,8 +2832,11 @@ static int smack_key_permission(key_ref_t key_ref,
> */
> if (cred->security == NULL)
> return -EACCES;
> + SMACK_AUDIT_DATA_INIT(&ad, KEY);
> + ad.u.key = keyp->serial;
> + ad.u.key_desc = keyp->description;
>
> - return smk_access(cred->security, keyp->security, MAY_READWRITE);
> + return smk_access_log(cred->security, keyp->security, MAY_READWRITE, &ad);
> }
> #endif /* CONFIG_KEYS */
>
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index 8e42800..923223f 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -27,6 +27,7 @@
> #include <linux/ctype.h>
> #include <linux/audit.h>
> #include "smack.h"
> +#include "smack_logging.h"
>
> /*
> * smackfs pseudo filesystem.
> @@ -41,6 +42,7 @@ enum smk_inos {
> SMK_AMBIENT = 7, /* internet ambient label */
> SMK_NETLBLADDR = 8, /* single label hosts */
> SMK_ONLYCAP = 9, /* the only "capable" label */
> + SMK_LOGGING = 10, /* logging */
> };
>
> /*
> @@ -1112,6 +1114,54 @@ static const struct file_operations smk_onlycap_ops = {
> .write = smk_write_onlycap,
> };
>
> +
> +static ssize_t smk_read_logging(struct file *filp, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char temp[32];
> + ssize_t rc;
> +
> + if (*ppos != 0)
> + return 0;
> +
> + sprintf(temp, "%d\n",
> + log_policy.log_denied + log_policy.log_accepted*2);
> + rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
> + return rc;
> +}
> +
> +static ssize_t smk_write_logging(struct file *file, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + char temp[32];
> + int i;
> +
> + if (!capable(CAP_MAC_ADMIN))
> + return -EPERM;
> +
> + if (count >= sizeof(temp) || count == 0)
> + return -EINVAL;
> +
> + if (copy_from_user(temp, buf, count) != 0)
> + return -EFAULT;
> +
> + temp[count] = '\0';
> +
> + if (sscanf(temp, "%d", &i) != 1)
> + return -EINVAL;
> + if (i < 0 || i > 3)
> + return -EINVAL;
> + log_policy.log_denied = i & 1;
> + log_policy.log_accepted = (i & 2) >> 1 ;
> + return count;
> +}
> +
> +
> +
> +static const struct file_operations smk_logging_ops = {
> + .read = smk_read_logging,
> + .write = smk_write_logging,
> +};
> /**
> * smk_fill_super - fill the /smackfs superblock
> * @sb: the empty superblock
> @@ -1142,6 +1192,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
> {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
> [SMK_ONLYCAP] =
> {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
> + [SMK_LOGGING] =
> + {"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
> /* last one */ {""}
> };
>
>
>
>
>
15 years, 9 months