Commit 93315ed6 authored by Amy Griffis's avatar Amy Griffis Committed by Al Viro

[PATCH] audit string fields interface + consumer

Updated patch to dynamically allocate audit rule fields in kernel's
internal representation.  Added unlikely() calls for testing memory
allocation result.

Amy Griffis wrote:     [Wed Jan 11 2006, 02:02:31PM EST]
> Modify audit's kernel-userspace interface to allow the specification
> of string fields in audit rules.
>
> Signed-off-by: Amy Griffis <amy.griffis@hp.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
(cherry picked from 5ffc4a863f92351b720fe3e9c5cd647accff9e03 commit)
parent af601e46
......@@ -50,15 +50,18 @@
*/
#define AUDIT_GET 1000 /* Get status */
#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */
#define AUDIT_LIST 1002 /* List syscall filtering rules */
#define AUDIT_ADD 1003 /* Add syscall filtering rule */
#define AUDIT_DEL 1004 /* Delete syscall filtering rule */
#define AUDIT_LIST 1002 /* List syscall rules -- deprecated */
#define AUDIT_ADD 1003 /* Add syscall rule -- deprecated */
#define AUDIT_DEL 1004 /* Delete syscall rule -- deprecated */
#define AUDIT_USER 1005 /* Message from userspace -- deprecated */
#define AUDIT_LOGIN 1006 /* Define the login id and information */
#define AUDIT_WATCH_INS 1007 /* Insert file/dir watch entry */
#define AUDIT_WATCH_REM 1008 /* Remove file/dir watch entry */
#define AUDIT_WATCH_LIST 1009 /* List all file/dir watches */
#define AUDIT_SIGNAL_INFO 1010 /* Get info about sender of signal to auditd */
#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */
#define AUDIT_USER_AVC 1107 /* We filter this differently */
......@@ -229,6 +232,26 @@ struct audit_status {
__u32 backlog; /* messages waiting in queue */
};
/* audit_rule_data supports filter rules with both integer and string
* fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
* AUDIT_LIST_RULES requests.
*/
struct audit_rule_data {
__u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
__u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
__u32 field_count;
__u32 mask[AUDIT_BITMASK_SIZE];
__u32 fields[AUDIT_MAX_FIELDS];
__u32 values[AUDIT_MAX_FIELDS];
__u32 fieldflags[AUDIT_MAX_FIELDS];
__u32 buflen; /* total length of string fields */
char buf[0]; /* string fields buffer */
};
/* audit_rule is supported to maintain backward compatibility with
* userspace. It supports integer fields only and corresponds to
* AUDIT_ADD, AUDIT_DEL and AUDIT_LIST requests.
*/
struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
__u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
__u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
......@@ -338,7 +361,7 @@ extern void audit_log_d_path(struct audit_buffer *ab,
extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
extern int audit_filter_type(int type);
extern int audit_receive_filter(int type, int pid, int uid, int seq,
void *data, uid_t loginuid);
void *data, size_t datasz, uid_t loginuid);
#else
#define audit_log(c,g,t,f,...) do { ; } while (0)
#define audit_log_start(c,g,t) ({ NULL; })
......
......@@ -52,6 +52,7 @@
#include <linux/audit.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
......@@ -361,9 +362,12 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
switch (msg_type) {
case AUDIT_GET:
case AUDIT_LIST:
case AUDIT_LIST_RULES:
case AUDIT_SET:
case AUDIT_ADD:
case AUDIT_ADD_RULE:
case AUDIT_DEL:
case AUDIT_DEL_RULE:
case AUDIT_SIGNAL_INFO:
if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
err = -EPERM;
......@@ -470,12 +474,23 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
break;
case AUDIT_ADD:
case AUDIT_DEL:
if (nlh->nlmsg_len < sizeof(struct audit_rule))
if (nlmsg_len(nlh) < sizeof(struct audit_rule))
return -EINVAL;
/* fallthrough */
case AUDIT_LIST:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
uid, seq, data, loginuid);
uid, seq, data, nlmsg_len(nlh),
loginuid);
break;
case AUDIT_ADD_RULE:
case AUDIT_DEL_RULE:
if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
return -EINVAL;
/* fallthrough */
case AUDIT_LIST_RULES:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
uid, seq, data, nlmsg_len(nlh),
loginuid);
break;
case AUDIT_SIGNAL_INFO:
sig_data.uid = audit_sig_uid;
......
......@@ -52,10 +52,27 @@ enum audit_state {
};
/* Rule lists */
struct audit_field {
u32 type;
u32 val;
u32 op;
};
struct audit_krule {
int vers_ops;
u32 flags;
u32 listnr;
u32 action;
u32 mask[AUDIT_BITMASK_SIZE];
u32 buflen; /* for data alloc on list rules */
u32 field_count;
struct audit_field *fields;
};
struct audit_entry {
struct list_head list;
struct rcu_head rcu;
struct audit_rule rule;
struct list_head list;
struct rcu_head rcu;
struct audit_krule rule;
};
......
This diff is collapsed.
......@@ -162,70 +162,68 @@ struct audit_context {
/* Compare a task_struct with an audit_rule. Return 1 on match, 0
* otherwise. */
static int audit_filter_rules(struct task_struct *tsk,
struct audit_rule *rule,
struct audit_krule *rule,
struct audit_context *ctx,
enum audit_state *state)
{
int i, j;
for (i = 0; i < rule->field_count; i++) {
u32 field = rule->fields[i] & ~AUDIT_OPERATORS;
u32 op = rule->fields[i] & AUDIT_OPERATORS;
u32 value = rule->values[i];
struct audit_field *f = &rule->fields[i];
int result = 0;
switch (field) {
switch (f->type) {
case AUDIT_PID:
result = audit_comparator(tsk->pid, op, value);
result = audit_comparator(tsk->pid, f->op, f->val);
break;
case AUDIT_UID:
result = audit_comparator(tsk->uid, op, value);
result = audit_comparator(tsk->uid, f->op, f->val);
break;
case AUDIT_EUID:
result = audit_comparator(tsk->euid, op, value);
result = audit_comparator(tsk->euid, f->op, f->val);
break;
case AUDIT_SUID:
result = audit_comparator(tsk->suid, op, value);
result = audit_comparator(tsk->suid, f->op, f->val);
break;
case AUDIT_FSUID:
result = audit_comparator(tsk->fsuid, op, value);
result = audit_comparator(tsk->fsuid, f->op, f->val);
break;
case AUDIT_GID:
result = audit_comparator(tsk->gid, op, value);
result = audit_comparator(tsk->gid, f->op, f->val);
break;
case AUDIT_EGID:
result = audit_comparator(tsk->egid, op, value);
result = audit_comparator(tsk->egid, f->op, f->val);
break;
case AUDIT_SGID:
result = audit_comparator(tsk->sgid, op, value);
result = audit_comparator(tsk->sgid, f->op, f->val);
break;
case AUDIT_FSGID:
result = audit_comparator(tsk->fsgid, op, value);
result = audit_comparator(tsk->fsgid, f->op, f->val);
break;
case AUDIT_PERS:
result = audit_comparator(tsk->personality, op, value);
result = audit_comparator(tsk->personality, f->op, f->val);
break;
case AUDIT_ARCH:
if (ctx)
result = audit_comparator(ctx->arch, op, value);
result = audit_comparator(ctx->arch, f->op, f->val);
break;
case AUDIT_EXIT:
if (ctx && ctx->return_valid)
result = audit_comparator(ctx->return_code, op, value);
result = audit_comparator(ctx->return_code, f->op, f->val);
break;
case AUDIT_SUCCESS:
if (ctx && ctx->return_valid) {
if (value)
result = audit_comparator(ctx->return_valid, op, AUDITSC_SUCCESS);
if (f->val)
result = audit_comparator(ctx->return_valid, f->op, AUDITSC_SUCCESS);
else
result = audit_comparator(ctx->return_valid, op, AUDITSC_FAILURE);
result = audit_comparator(ctx->return_valid, f->op, AUDITSC_FAILURE);
}
break;
case AUDIT_DEVMAJOR:
if (ctx) {
for (j = 0; j < ctx->name_count; j++) {
if (audit_comparator(MAJOR(ctx->names[j].dev), op, value)) {
if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) {
++result;
break;
}
......@@ -235,7 +233,7 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_DEVMINOR:
if (ctx) {
for (j = 0; j < ctx->name_count; j++) {
if (audit_comparator(MINOR(ctx->names[j].dev), op, value)) {
if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) {
++result;
break;
}
......@@ -245,8 +243,8 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_INODE:
if (ctx) {
for (j = 0; j < ctx->name_count; j++) {
if (audit_comparator(ctx->names[j].ino, op, value) ||
audit_comparator(ctx->names[j].pino, op, value)) {
if (audit_comparator(ctx->names[j].ino, f->op, f->val) ||
audit_comparator(ctx->names[j].pino, f->op, f->val)) {
++result;
break;
}
......@@ -256,14 +254,14 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_LOGINUID:
result = 0;
if (ctx)
result = audit_comparator(ctx->loginuid, op, value);
result = audit_comparator(ctx->loginuid, f->op, f->val);
break;
case AUDIT_ARG0:
case AUDIT_ARG1:
case AUDIT_ARG2:
case AUDIT_ARG3:
if (ctx)
result = audit_comparator(ctx->argv[field-AUDIT_ARG0], op, value);
result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
break;
}
......
......@@ -99,6 +99,9 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
{ AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
{ AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
{ AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
{ AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment