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 @@ ...@@ -50,15 +50,18 @@
*/ */
#define AUDIT_GET 1000 /* Get status */ #define AUDIT_GET 1000 /* Get status */
#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ #define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */
#define AUDIT_LIST 1002 /* List syscall filtering rules */ #define AUDIT_LIST 1002 /* List syscall rules -- deprecated */
#define AUDIT_ADD 1003 /* Add syscall filtering rule */ #define AUDIT_ADD 1003 /* Add syscall rule -- deprecated */
#define AUDIT_DEL 1004 /* Delete syscall filtering rule */ #define AUDIT_DEL 1004 /* Delete syscall rule -- deprecated */
#define AUDIT_USER 1005 /* Message from userspace -- deprecated */ #define AUDIT_USER 1005 /* Message from userspace -- deprecated */
#define AUDIT_LOGIN 1006 /* Define the login id and information */ #define AUDIT_LOGIN 1006 /* Define the login id and information */
#define AUDIT_WATCH_INS 1007 /* Insert file/dir watch entry */ #define AUDIT_WATCH_INS 1007 /* Insert file/dir watch entry */
#define AUDIT_WATCH_REM 1008 /* Remove 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_WATCH_LIST 1009 /* List all file/dir watches */
#define AUDIT_SIGNAL_INFO 1010 /* Get info about sender of signal to auditd */ #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_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */
#define AUDIT_USER_AVC 1107 /* We filter this differently */ #define AUDIT_USER_AVC 1107 /* We filter this differently */
...@@ -229,6 +232,26 @@ struct audit_status { ...@@ -229,6 +232,26 @@ struct audit_status {
__u32 backlog; /* messages waiting in queue */ __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 */ struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
__u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */ __u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
__u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */ __u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
...@@ -338,7 +361,7 @@ extern void audit_log_d_path(struct audit_buffer *ab, ...@@ -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_user(struct netlink_skb_parms *cb, int type);
extern int audit_filter_type(int type); extern int audit_filter_type(int type);
extern int audit_receive_filter(int type, int pid, int uid, int seq, 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 #else
#define audit_log(c,g,t,f,...) do { ; } while (0) #define audit_log(c,g,t,f,...) do { ; } while (0)
#define audit_log_start(c,g,t) ({ NULL; }) #define audit_log_start(c,g,t) ({ NULL; })
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <linux/audit.h> #include <linux/audit.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/netlink.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netlink.h> #include <linux/netlink.h>
...@@ -361,9 +362,12 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type) ...@@ -361,9 +362,12 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
switch (msg_type) { switch (msg_type) {
case AUDIT_GET: case AUDIT_GET:
case AUDIT_LIST: case AUDIT_LIST:
case AUDIT_LIST_RULES:
case AUDIT_SET: case AUDIT_SET:
case AUDIT_ADD: case AUDIT_ADD:
case AUDIT_ADD_RULE:
case AUDIT_DEL: case AUDIT_DEL:
case AUDIT_DEL_RULE:
case AUDIT_SIGNAL_INFO: case AUDIT_SIGNAL_INFO:
if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL)) if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
err = -EPERM; err = -EPERM;
...@@ -470,12 +474,23 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -470,12 +474,23 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
break; break;
case AUDIT_ADD: case AUDIT_ADD:
case AUDIT_DEL: case AUDIT_DEL:
if (nlh->nlmsg_len < sizeof(struct audit_rule)) if (nlmsg_len(nlh) < sizeof(struct audit_rule))
return -EINVAL; return -EINVAL;
/* fallthrough */ /* fallthrough */
case AUDIT_LIST: case AUDIT_LIST:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, 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; break;
case AUDIT_SIGNAL_INFO: case AUDIT_SIGNAL_INFO:
sig_data.uid = audit_sig_uid; sig_data.uid = audit_sig_uid;
......
...@@ -52,10 +52,27 @@ enum audit_state { ...@@ -52,10 +52,27 @@ enum audit_state {
}; };
/* Rule lists */ /* 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 audit_entry {
struct list_head list; struct list_head list;
struct rcu_head rcu; struct rcu_head rcu;
struct audit_rule rule; struct audit_krule rule;
}; };
......
This diff is collapsed.
...@@ -162,70 +162,68 @@ struct audit_context { ...@@ -162,70 +162,68 @@ struct audit_context {
/* Compare a task_struct with an audit_rule. Return 1 on match, 0 /* Compare a task_struct with an audit_rule. Return 1 on match, 0
* otherwise. */ * otherwise. */
static int audit_filter_rules(struct task_struct *tsk, static int audit_filter_rules(struct task_struct *tsk,
struct audit_rule *rule, struct audit_krule *rule,
struct audit_context *ctx, struct audit_context *ctx,
enum audit_state *state) enum audit_state *state)
{ {
int i, j; int i, j;
for (i = 0; i < rule->field_count; i++) { for (i = 0; i < rule->field_count; i++) {
u32 field = rule->fields[i] & ~AUDIT_OPERATORS; struct audit_field *f = &rule->fields[i];
u32 op = rule->fields[i] & AUDIT_OPERATORS;
u32 value = rule->values[i];
int result = 0; int result = 0;
switch (field) { switch (f->type) {
case AUDIT_PID: case AUDIT_PID:
result = audit_comparator(tsk->pid, op, value); result = audit_comparator(tsk->pid, f->op, f->val);
break; break;
case AUDIT_UID: case AUDIT_UID:
result = audit_comparator(tsk->uid, op, value); result = audit_comparator(tsk->uid, f->op, f->val);
break; break;
case AUDIT_EUID: case AUDIT_EUID:
result = audit_comparator(tsk->euid, op, value); result = audit_comparator(tsk->euid, f->op, f->val);
break; break;
case AUDIT_SUID: case AUDIT_SUID:
result = audit_comparator(tsk->suid, op, value); result = audit_comparator(tsk->suid, f->op, f->val);
break; break;
case AUDIT_FSUID: case AUDIT_FSUID:
result = audit_comparator(tsk->fsuid, op, value); result = audit_comparator(tsk->fsuid, f->op, f->val);
break; break;
case AUDIT_GID: case AUDIT_GID:
result = audit_comparator(tsk->gid, op, value); result = audit_comparator(tsk->gid, f->op, f->val);
break; break;
case AUDIT_EGID: case AUDIT_EGID:
result = audit_comparator(tsk->egid, op, value); result = audit_comparator(tsk->egid, f->op, f->val);
break; break;
case AUDIT_SGID: case AUDIT_SGID:
result = audit_comparator(tsk->sgid, op, value); result = audit_comparator(tsk->sgid, f->op, f->val);
break; break;
case AUDIT_FSGID: case AUDIT_FSGID:
result = audit_comparator(tsk->fsgid, op, value); result = audit_comparator(tsk->fsgid, f->op, f->val);
break; break;
case AUDIT_PERS: case AUDIT_PERS:
result = audit_comparator(tsk->personality, op, value); result = audit_comparator(tsk->personality, f->op, f->val);
break; break;
case AUDIT_ARCH: case AUDIT_ARCH:
if (ctx) if (ctx)
result = audit_comparator(ctx->arch, op, value); result = audit_comparator(ctx->arch, f->op, f->val);
break; break;
case AUDIT_EXIT: case AUDIT_EXIT:
if (ctx && ctx->return_valid) if (ctx && ctx->return_valid)
result = audit_comparator(ctx->return_code, op, value); result = audit_comparator(ctx->return_code, f->op, f->val);
break; break;
case AUDIT_SUCCESS: case AUDIT_SUCCESS:
if (ctx && ctx->return_valid) { if (ctx && ctx->return_valid) {
if (value) if (f->val)
result = audit_comparator(ctx->return_valid, op, AUDITSC_SUCCESS); result = audit_comparator(ctx->return_valid, f->op, AUDITSC_SUCCESS);
else else
result = audit_comparator(ctx->return_valid, op, AUDITSC_FAILURE); result = audit_comparator(ctx->return_valid, f->op, AUDITSC_FAILURE);
} }
break; break;
case AUDIT_DEVMAJOR: case AUDIT_DEVMAJOR:
if (ctx) { if (ctx) {
for (j = 0; j < ctx->name_count; j++) { 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; ++result;
break; break;
} }
...@@ -235,7 +233,7 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -235,7 +233,7 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_DEVMINOR: case AUDIT_DEVMINOR:
if (ctx) { if (ctx) {
for (j = 0; j < ctx->name_count; j++) { 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; ++result;
break; break;
} }
...@@ -245,8 +243,8 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -245,8 +243,8 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_INODE: case AUDIT_INODE:
if (ctx) { if (ctx) {
for (j = 0; j < ctx->name_count; j++) { for (j = 0; j < ctx->name_count; j++) {
if (audit_comparator(ctx->names[j].ino, op, value) || if (audit_comparator(ctx->names[j].ino, f->op, f->val) ||
audit_comparator(ctx->names[j].pino, op, value)) { audit_comparator(ctx->names[j].pino, f->op, f->val)) {
++result; ++result;
break; break;
} }
...@@ -256,14 +254,14 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -256,14 +254,14 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_LOGINUID: case AUDIT_LOGINUID:
result = 0; result = 0;
if (ctx) if (ctx)
result = audit_comparator(ctx->loginuid, op, value); result = audit_comparator(ctx->loginuid, f->op, f->val);
break; break;
case AUDIT_ARG0: case AUDIT_ARG0:
case AUDIT_ARG1: case AUDIT_ARG1:
case AUDIT_ARG2: case AUDIT_ARG2:
case AUDIT_ARG3: case AUDIT_ARG3:
if (ctx) 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; break;
} }
......
...@@ -99,6 +99,9 @@ static struct nlmsg_perm nlmsg_audit_perms[] = ...@@ -99,6 +99,9 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
{ AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV }, { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
{ AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_DEL, 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_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
{ AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, { 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