Audit implementation idea.
Pawel Jakub Dawidek
nick at garage.freebsd.pl
Fri May 2 13:51:28 GMT 2003
Hello...
Because there is many problems with events auditing implementation I want
to share some ideas of how it could be implemented.
One of the biggest problem with audit is syscalls arguments handling.
I think I've found a clean way to avoid any potential races, etc.
Proposed implementation isn't a fast hack, but take a look.
For every syscall argument that is a buffer there have to be an argument
which describe its size or not, if size of buffer is constant.
First of all we should copy arguments from userland to kernel space and
teach syscalls to use buffers that are in kernel space.
Because of lots of differents in arguments my idea is to write functions
for every syscall only for argument copy operations.
Let's modify sysent struct:
struct sysent {
int sy_narg;
sy_call_t *sy_call;
sy_args_t *sy_args;
};
typedef int sy_args_t(struct thread *, void *, struct karg *);
Needed struct to describe argument:
struct karg {
union {
register_t __ka_u_arg;
void *__ka_u_buf;
int __ka_u_int;
long __ka_u_long;
} __ka_u_value;
size_t ka_size; /* size of buffer when ka_type is KARG_BUF
* or 0 in different cases. */
u_int ka_type;
};
#define ka_arg __ka_u_value.__ka_u_arg
#define ka_buf __ka_u_value.__ka_u_buf
#define ka_int __ka_u_value.__ka_u_int
#define ka_long __ka_u_value.__ka_u_long
#define KARG_INT 0x0
#define KARG_BUF 0x1
#define KARG_LONG 0x2
#define KARG_MASK 0xf
#define KARG_DIR_IN 0x10
#define KARG_DIR_OUT 0x20
#define KARG_DIR_INOUT (KARG_DIR_IN | KARG_DIR_OUT)
#define KARG_DIR_MASK 0xf0
When ORing KARG_(INT|BUF|LONG) with KARG_DIR_* we got argument type and
information if this is a buffer that imports some data (KARG_DIR_IN) to
kernel, that will be filled out by kernel (KARG_DIR_OUT) or both
(KARG_DIR_INOUT).
Now some modifications in trap.c:
[...]
if (error == 0) {
struct karg *kargs = NULL;
void *syargs = NULL;
int i;
td->td_retval[0] = 0;
td->td_retval[1] = frame.tf_edx;
STOPEVENT(p, S_SCE, narg);
if (*callp->sy_args == NULL) {
error = (*callp->sy_call)(td, args);
goto noaudit;
}
if (narg != 0) {
kargs = malloc(sizeof(struct karg) * narg, M_KARG,
M_NOWAIT);
if (kargs == NULL) {
error = ENOMEM;
goto fail;
}
syargs = malloc(sizeof(register_t) * narg, M_KARG,
M_NOWAIT);
if (syargs == NULL) {
free(kargs, M_KARG);
kargs = NULL;
error = ENOMEM;
goto fail;
}
}
error = (*callp->sy_args)(td, args, kargs);
if (error != 0) {
kargs = NULL;
goto fail;
}
/* 'long' arguments aren't supported in this example. */
for (i = 0; i < narg; ++i)
(register_t)syargs[i] = kargs[i]->ka_arg;
audit_before_syscall(td, kargs, code, narg);
error = (*callp->sy_call)(td, syargs);
if (error == 0) {
/* Fill out-buffers. */
error = copy_args(args, kargs);
}
fail:
/*
* Note that in some cases this function could be called
* without audit_before_syscall() earlier.
*/
audit_after_syscall(td, kargs, code, narg, error);
noaudit:
}
Now example of arguments handling function:
int
rename_args_proc(struct thread *td, struct rename_args *uap, struct karg *kargs)
{
char *from, *to;
size_t fromsize, tosize;
from = malloc(MAXPATHLEN, M_KARG, M_NOWAIT);
if (from == NULL)
return (ENOMEM);
error = copyinstr(SCARG(uap, from), from, MAXPATHLEN, &fromsize);
if (error != 0) {
free(from, M_KARG);
return (error);
}
to = malloc(MAXPATHLEN, M_KARG, M_NOWAIT);
if (to == NULL) {
free(from, M_KARG);
return (ENOMEM);
}
error = copyinstr(SCARG(uap, to), to, MAXPATHLEN, &tosize);
if (error != 0) {
free(from, M_KARG);
free(to, M_KARG);
return (error);
}
kargs[0]->ka_ptr = from;
kargs[0]->ka_size = fromsize;
kargs[0]->ka_type = KARG_BUF | KARG_DIR_IN;
kargs[1]->ka_ptr = to;
kargs[1]->ka_size = tosize;
kargs[1]->ka_type = KARG_BUF | KARG_DIR_IN;
return (0);
}
There should be also some standard function for arguments handling when
argument are 'int's only, because if sy_args is NULL that means that syscall
doesn't support auditing yet and will be called in old way.
Maybe there will be need to write per-syscall functions to fill out buffers,
but I think there is chance to avoid this.
We should also remove all copy(9) functions from original syscalls.
With this infrastructure audit functionality could be imported in little
steps.
What you think about it? Maybe there are other ideas to implement events
auditing?
--
Pawel Jakub Dawidek pawel at dawidek.net
UNIX Systems Programmer/Administrator http://garage.freebsd.pl
Am I Evil? Yes, I Am! http://cerber.sourceforge.net
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 305 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/trustedbsd-audit/attachments/20030502/6ae255ce/attachment.bin
More information about the trustedbsd-audit
mailing list