Hello,
This patch is to keep in sync with kernel Patch #7U3. It fixes a buggy
rules and watches listing feature and has been modified to work with the
new kernel rules and watches listing interface. The user space rules
and watches listing feature would try to list both rules and watches all
in one get_reply() (with one NLMSG_DONE), but didn't get this right. As
a consequence, rules were not being listed, because it was exiting the
get_reply() before it had a chance. Once I fixed this bug, I discovered
another bug in the kernel related to listing rules and watches which was
addressed in the kernel Patch #7U3. This bug is described in the e-mail
containing Patch #7U3.
I'm also sorry that this patch is not available for the latest audit
user space patch. I know it makes it really hard to sync user space
with kernel space and having to keep rebuilding a user space package and
kernel is annoying to boot. When Steve is ready, he'll adapt/merge this
code up to the latest version of the audit user package.
-tim
diff -Nurp audit-0.6.10/lib/libaudit.c auditfs~audit-0.6.10/lib/libaudit.c
--- audit-0.6.10/lib/libaudit.c 2005-03-31 16:04:57.000000000 -0600
+++ auditfs~audit-0.6.10/lib/libaudit.c 2005-04-27 17:35:49.000000000 -0500
@@ -194,7 +194,16 @@ int audit_set_backlog_limit(int fd, int
return rc;
}
-int audit_request_list(int fd)
+int audit_request_list_watches(int fd)
+{
+ int rc = audit_send(fd, AUDIT_WATCH_LIST, NULL, 0);
+ if (rc < 0)
+ msg(LOG_WARNING, "Error sending list request (%s)",
+ strerror(-rc));
+ return rc;
+}
+
+int audit_request_list_rules(int fd)
{
int rc = audit_send(fd, AUDIT_LIST, NULL, 0);
if (rc < 0)
@@ -203,18 +212,44 @@ int audit_request_list(int fd)
return rc;
}
-int audit_insert_watch(int fd, struct audit_watch *req)
+int audit_insert_watch(int fd, struct audit_transport *req, char **buf)
{
- int rc = audit_send(fd, AUDIT_WATCH_INS, req, sizeof(*req));
+ void *memblk = NULL;
+ unsigned int offset, total;
+
+ total = sizeof(*req) + req->pathlen + req->fklen;
+ memblk = (void*)malloc(total);
+ if (!memblk)
+ return -1;
+
+ memcpy(memblk, req, sizeof(*req));
+ offset = total - req->fklen;
+ memcpy(memblk + offset, buf[1], req->fklen);
+ offset = offset - req->pathlen;
+ memcpy(memblk + offset, buf[0], req->pathlen);
+
+ int rc = audit_send(fd, AUDIT_WATCH_INS, memblk, total);
if (rc < 0)
msg(LOG_WARNING, "Error sending watch insert request (%s)",
strerror(-rc));
return rc;
}
-int audit_remove_watch(int fd, struct audit_watch *req)
+int audit_remove_watch(int fd, struct audit_transport *req, char **buf)
{
- int rc = audit_send(fd, AUDIT_WATCH_REM, req, sizeof(*req));
+ void *memblk = NULL;
+ unsigned int offset, total;
+
+ total = sizeof(*req) + req->pathlen;
+ memblk = (void*)malloc(total);
+ if (!memblk)
+ return -1;
+
+ memcpy(memblk, req, sizeof(*req));
+ offset = total - req->pathlen;
+ memcpy(memblk + offset, buf[0], req->pathlen);
+
+ int rc = audit_send(fd, AUDIT_WATCH_REM, memblk, total);
if (rc < 0)
msg(LOG_WARNING, "Error sending watch remove request (%s)",
strerror(-rc));
diff -Nurp audit-0.6.10/lib/libaudit.h auditfs~audit-0.6.10/lib/libaudit.h
--- audit-0.6.10/lib/libaudit.h 2005-04-01 12:29:48.000000000 -0600
+++ auditfs~audit-0.6.10/lib/libaudit.h 2005-04-27 17:35:43.000000000 -0500
@@ -42,11 +42,22 @@
#define AUDIT_WATCH_LIST 1009
struct audit_watch {
- uint32_t namelen;
- uint32_t fklen;
- char *name;
- char *filterkey;
- uint32_t perms;
+ uint32_t dev_major;
+ uint32_t dev_minor;
+ char *path;
+ char *filterkey;
+ uint32_t perms;
+ uint32_t valid;
+};
+
+struct audit_transport {
+ uint32_t dev_major;
+ uint32_t dev_minor;
+ uint32_t perms;
+ uint32_t valid;
+ uint32_t pathlen;
+ uint32_t fklen;
+ char buf[0];
};
/* 32 byte max key size */
#define AUDIT_FILTERKEY_MAX 32
@@ -57,15 +68,15 @@ struct audit_watch {
struct audit_reply {
struct audit_message msg;
- int type;
- int len;
- struct nlmsghdr *nlh;
- struct audit_status *status;
- struct audit_rule *rule;
- struct audit_login *login;
- const char *message;
- struct nlmsgerr *error;
- int watch;
+ int type;
+ int len;
+ struct nlmsghdr *nlh;
+ struct audit_status *status;
+ struct audit_rule *rule;
+ struct audit_login *login;
+ struct audit_transport *watch;
+ const char *message;
+ struct nlmsgerr *error;
};
struct auditd_reply_list {
@@ -117,11 +128,12 @@ extern int audit_set_rate_limit(int fd,
extern int audit_set_backlog_limit(int fd, int limit);
/* AUDIT_LIST */
-extern int audit_request_list(int fd);
+extern int audit_request_list_rules(int fd);
+extern int audit_request_list_watches(int fd);
/* AUDIT_WATCH */
-extern int audit_insert_watch(int fd, struct audit_watch *req);
-extern int audit_remove_watch(int fd, struct audit_watch *req);
+extern int audit_insert_watch(int fd, struct audit_transport *req, char **buf);
+extern int audit_remove_watch(int fd, struct audit_transport *req, char **buf);
/* AUDIT_ADD */
extern int audit_add_rule(int fd, struct audit_rule *rule,
diff -Nurp audit-0.6.10/lib/netlink.c auditfs~audit-0.6.10/lib/netlink.c
--- audit-0.6.10/lib/netlink.c 2005-03-31 16:04:57.000000000 -0600
+++ auditfs~audit-0.6.10/lib/netlink.c 2005-04-27 17:37:12.000000000 -0500
@@ -133,7 +133,7 @@ static int adjust_reply(struct audit_rep
rep->rule = NULL;
rep->message = NULL;
rep->error = NULL;
- rep->watch = 0;
+ rep->watch = NULL;
if (!NLMSG_OK(rep->nlh, (unsigned int)len))
return 0;
switch (rep->type) {
@@ -153,7 +153,8 @@ static int adjust_reply(struct audit_rep
break;
case AUDIT_WATCH_INS:
case AUDIT_WATCH_REM:
- memcpy(&rep->watch, NLMSG_DATA(rep->nlh), sizeof(int));
+ case AUDIT_WATCH_LIST:
+ rep->watch = NLMSG_DATA(rep->nlh);
break;
}
return len;
diff -Nurp audit-0.6.10/src/auditctl.c auditfs~audit-0.6.10/src/auditctl.c
--- audit-0.6.10/src/auditctl.c 2005-04-01 13:06:42.000000000 -0600
+++ auditfs~audit-0.6.10/src/auditctl.c 2005-04-27 17:40:01.000000000 -0500
@@ -67,6 +67,7 @@ static int delete_all_rules(void);
/* Global vars */
static int fd = -1;
+static int list_request = 0;
static int list_requested = 0;
static int syscalladded = 0;
static int add = 0, del = 0, action = 0;
@@ -74,6 +75,8 @@ static int ins = 0, rem = 0;
static struct audit_rule rule;
static struct audit_watch watch;
+static struct audit_transport wreq;
+static char *wreq_buf[2] = {NULL, NULL};
/*
* This function will reset everything used for each loop when loading
@@ -81,6 +84,7 @@ static struct audit_watch watch;
*/
static int reset_vars(void)
{
+ list_request = 0;
list_requested = 0;
syscalladded = 0;
add = 0;
@@ -90,7 +94,7 @@ static int reset_vars(void)
rem = 0;
memset(&rule, 0, sizeof(rule));
- memset(&watch, 0, sizeof(watch));
+ memset(&wreq, 0, sizeof(wreq));
if ((fd = audit_open()) < 0) {
fprintf(stderr, "Cannot open netlink audit socket\n");
return 1;
@@ -116,7 +120,8 @@ static void usage(void)
" -k <key> Set filterkey on watch\n"
" -l List rules\n"
" -m text Send a user-space message\n"
- " -p [r|w|e|a] Set permissions filter on watch:\n"
+ " -p [r|w|e|a] Set permissions filter on watch\n"
+ " r=read, w=write, e=execute, a=append\n"
" -r <rate> Set limit in messages/sec (0=none)\n"
" -R <file> read rules from file\n"
" -s Report status\n"
@@ -125,7 +130,6 @@ static void usage(void)
" -v Version\n"
" -w <path> Insert watch at <path>\n"
" -W <path> Remove watch at <path>\n"
- " r=read, w=write, e=execute, a=append\n"
);
}
@@ -183,24 +187,47 @@ static int check_path(const char *path)
return 0;
}
+static int make_watch(struct audit_transport *wreq, struct audit_watch *watch)
+{
+ watch->path = (char*)malloc(wreq->pathlen);
+ if (!watch->path)
+ return 0;
+
+ memcpy(watch->path, wreq->buf, wreq->pathlen);
+
+ if (wreq->fklen) {
+ watch->filterkey = (char*)malloc(wreq->fklen);
+ if (!watch->filterkey) {
+ free(watch->path);
+ return 0;
+ }
+ }
+
+ memcpy(watch->filterkey, wreq->buf+wreq->pathlen, wreq->fklen);
+
+ watch->dev_major = wreq->dev_major;
+ watch->dev_minor = wreq->dev_minor;
+ watch->perms = wreq->perms;
+ watch->valid = wreq->valid;
+
+ return 1;
+}
+
/*
- * Setup a watch. The "name" of the watch in userspace will be the
<path> to
- * the watch. When this potential watch reaches the kernel, it will resolve
- * down to <name> (of terminating file or directory).
* Returns a 1 on success & -1 on failure.
*/
-static int audit_setup_watch_name(struct audit_watch *req, const char *opt,
+static int audit_setup_watch_path(struct audit_transport *req, const char *opt,
int *act)
{
- if (!req->name) {
+ if (!wreq_buf[0]) {
if (check_path(opt))
return -1;
- req->name = strdup(opt);
- if (!req->name) {
+ wreq_buf[0] = strdup(opt);
+ if (!wreq_buf[0]) {
fprintf(stderr, "Out of memory\n");
return -1;
}
- req->namelen = strlen(req->name) + 1;
+ req->pathlen = strlen(wreq_buf[0]) + 1;
*act = 1;
return 1;
}
@@ -212,18 +239,18 @@ static int audit_setup_watch_name(struct
* Setup a filterkey for the watch.
* Returns a 1 on success & -1 on failure.
*/
-static int audit_setup_filterkey(struct audit_watch *req, const char *opt)
+static int audit_setup_filterkey(struct audit_transport *req, const char *opt)
{
- if (!req->filterkey) {
- req->filterkey = strdup(opt);
- if (!req->filterkey) {
+ if (!wreq_buf[1]) {
+ wreq_buf[1] = strdup(opt);
+ if (!wreq_buf[1]) {
fprintf(stderr, "Out of memory\n");
return -1;
}
req->fklen = strlen(opt) + 1;
if (req->fklen > AUDIT_FILTERKEY_MAX) {
fprintf(stderr, "The filterkey is too big\n");
- free(req->filterkey);
+ free(wreq_buf[1]);
return -1;
}
return 1;
@@ -236,7 +263,7 @@ static int audit_setup_filterkey(struct
* Setup a watch permissions.
* Returns a 1 on success & -1 on failure.
*/
-static int audit_setup_perms(struct audit_watch *req, const char *opt)
+static int audit_setup_perms(struct audit_transport *req, const char *opt)
{
int i;
@@ -283,6 +310,23 @@ audit_watch_setup_exit:
return -1;
}
+int audit_request_list(int fd) {
+ if (audit_request_list_rules(fd)) {
+ list_requested = 1;
+ get_reply();
+ } else {
+ fprintf(stderr, "Error requesting rules list\n");
+ return -1;
+ }
+ if (audit_request_list_watches(fd)) {
+ list_requested = 1;
+ get_reply();
+ } else {
+ fprintf(stderr, "Error requesting watches list\n");
+ return -1;
+ }
+}
+
/*
* returns: < 0 error - noreply, 0 success - reply, > 0 success - rule
@@ -352,10 +396,7 @@ static int setopt(int count, char *vars[
}
break;
case 'l':
- if (audit_request_list(fd))
- list_requested = 1;
- else
- retval = -1;
+ list_request = 1;
break;
case 'a':
if (strstr(optarg, "task") && syscalladded) {
@@ -453,7 +494,7 @@ static int setopt(int count, char *vars[
break;
case 'w':
if (optarg)
- retval = audit_setup_watch_name(&watch, optarg, &ins);
+ retval = audit_setup_watch_path(&wreq, optarg, &ins);
else {
fprintf(stderr, "watch option needs a path\n");
retval = -1;
@@ -461,7 +502,7 @@ static int setopt(int count, char *vars[
break;
case 'W':
if (optarg)
- retval = audit_setup_watch_name(&watch, optarg, &rem);
+ retval = audit_setup_watch_path(&wreq, optarg, &rem);
else {
fprintf(stderr, "watch option needs a path\n");
retval = -1;
@@ -478,7 +519,7 @@ static int setopt(int count, char *vars[
retval = -1;
}
else
- retval = audit_setup_filterkey(&watch, optarg);
+ retval = audit_setup_filterkey(&wreq, optarg);
break;
case 'p':
if (!ins) {
@@ -491,7 +532,7 @@ static int setopt(int count, char *vars[
retval = -1;
}
else
- retval = audit_setup_perms(&watch, optarg);
+ retval = audit_setup_perms(&wreq, optarg);
break;
case 'v':
printf("auditctl version %s\n", VERSION);
@@ -655,32 +696,29 @@ int main(int argc, char *argv[])
*/
static int handle_request(int status)
{
- if (status == 0)
- get_reply();
- else if (status > 0) {
+ if (status == 0) {
+ if (list_request)
+ status = audit_request_list(fd);
+ else
+ get_reply();
+ } else if (status > 0) {
int rc;
if (add & 0x07)
rc = audit_add_rule(fd, &rule, add, action);
else if (del & 0x07)
rc = audit_delete_rule(fd, &rule, del, action);
else if (ins && !rem)
- rc = audit_insert_watch(fd, &watch);
+ rc = audit_insert_watch(fd, &wreq, wreq_buf);
else if (rem && !ins)
- rc = audit_remove_watch(fd, &watch);
+ rc = audit_remove_watch(fd, &wreq, wreq_buf);
else {
usage();
audit_close(fd);
exit(1);
}
- if (rc > 0) {
- if (audit_request_list(fd) > 0) {
- list_requested = 1;
- get_reply();
- } else {
- fprintf(stderr, "Error requesting list\n");
- status = -1;
- }
- } else {
+ if (rc > 0)
+ status = audit_request_list(fd);
+ else {
fprintf(stderr, "Error sending rule to kernel\n");
status = -1;
}
@@ -729,8 +767,6 @@ static int audit_print_reply(struct audi
case NLMSG_NOOP:
return 1;
case NLMSG_DONE:
- if (list_requested)
- printf("No rules\n");
return 0;
case NLMSG_ERROR:
printf("NLMSG_ERROR %d (%s) type=%d seq=%d\n",
@@ -797,6 +833,21 @@ static int audit_print_reply(struct audi
}
printf("\n");
return 1; /* get more messages until NLMSG_DONE */
+ case AUDIT_WATCH_LIST: {
+ int ret = make_watch(rep->watch, &watch);
+ if (!ret)
+ return ret;
+ list_requested = 0;
+ printf("AUDIT_WATCH_LIST: dev=%u:%u, path=%s, "
+ "filterkey=%s, perms=%u, valid=%d\n",
+ watch.dev_major, watch.dev_minor, watch.path,
+ watch.filterkey, watch.perms, watch.valid);
+
+ free(watch.path);
+ free(watch.filterkey);
+ memset(&watch, 0, sizeof(watch));
+ }
+ return 1;
default:
printf("Unknown: type=%d, len=%d\n", rep->type,
rep->nlh->nlmsg_len);
@@ -811,7 +862,7 @@ static int delete_all_rules(void)
struct audit_reply rep;
/* list the rules */
- rc = audit_request_list(fd);
+ rc = audit_request_list_rules(fd);
if (rc <= 0)
return -1;
@@ -842,7 +893,7 @@ static int delete_all_rules(void)
/* Finish by proving we are empty */
list_requested = 1;
- if (audit_request_list(fd) < 0)
+ if (audit_request_list_rules(fd) < 0)
return -1;
else
return 0;