redmine

Porting to FreeBSD, chapter 7: untested BSM support

... ... @@ -31,6 +31,8 @@ enum eventobjtype {
EOT_DOESNTEXIST = 1, // Doesn't exists (not created yet or already deleted)
EOT_FILE = 2, // File
EOT_DIR = 3, // Directory
// The value cannot be higher than "65535". It's due to recognize_event() function of mon_*.c
};
typedef enum eventobjtype eventobjtype_t;
... ...
... ... @@ -133,6 +133,7 @@ enum notifyengine_enum {
NE_FANOTIFY,
NE_INOTIFY,
NE_KQUEUE,
NE_BSM,
};
typedef enum notifyengine_enum notifyengine_t;
... ... @@ -283,11 +284,5 @@ struct sighandler_arg {
};
typedef struct sighandler_arg sighandler_arg_t;
enum unified_evetnmask {
UEM_DIR = 0x01,
UEM_CREATED = 0x02,
UEM_DELETED = 0x04,
};
#endif
... ...
... ... @@ -85,13 +85,15 @@
// size of event chain size to be processes at a time
#define KQUEUE_EVENTLISTSIZE 256
#define AUDITPIPE_PATH "/dev/auditpipe"
#define AUDIT_CONTROL_PATH "/etc/security/audit_control"
#define AUDIT_CONTROL_INITSCRIPT "/etc/rc.d/auditd"
#define AUDIT_CONTROL_HEADER "#clsync\n"
#define AUDIT_CONTROL_CONTENT "\n\
dir:/var/audit\n\
flags:fc,fd,fw,fm\n\
flags:fc,fd,fw,fm,cl\n\
minfree:0\n\
naflags:fc,fd,fw,fm\n\
naflags:fc,fd,fw,fm,cl\n\
policy:cnt\n\
filesz:1M\n\
"
... ...
... ... @@ -151,7 +151,7 @@ AC_ARG_WITH(bsm,
AS_HELP_STRING(--with-bsm,
[Enable BSM (Sun/*BSD audit) support as FS monitor subsystem; values: no, native, check; default: check]),
[],
[with_inotify=check]
[with_bsm=check]
)
case "$with_kqueue" in
... ...
... ... @@ -169,7 +169,7 @@ struct api_functs {
typedef struct api_functs api_functs_t;
struct notifyenginefuncts {
int (*wait)(struct ctx *ctx_p, struct timeval *tv_p);
int (*wait)(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *tv_p);
int (*handle)(struct ctx *ctx_p, struct indexes *indexes_p);
int (*add_watch_dir)(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath);
};
... ...
... ... @@ -879,11 +879,9 @@ is big enough (in FreeBSD).
CPU/HDD expensive way.
.B Not well tested. Use with caution!
.br
.B Warning! May be problems with hard links.
FreeBSD users: notify me about found bugs, please. And before the bugfix
you can switch to "inotify" through libinotify or to "bsm".
FreeBSD users: notify me about found bugs or performance issues, please. And
before the bugfix you can switch to "inotify" through libinotify or to "bsm".
.RE
.IR bsm
.RS
... ... @@ -899,21 +897,23 @@ can setup audit to watch FS events and report it into log. After that
will just parse the log via
.BR auditpipe "(4) [FreeBSD]."
Fast (relative to
.BR kqueue ),
reliable, but hacky way. It requires global audit reconfiguration that
Reliable, but hacky way. It requires global audit reconfiguration that
may hopple audit analysis.
.B Use with caution!
File /etc/security/audit_control will be overwritten with:
.B Not well tested. Use with caution!
Also file /etc/security/audit_control will be overwritten with:
.RS
#clsync
.br
.br
dir:/var/audit
.br
flags:fc,fd,fw,fm
flags:fc,fd,fw,fm,cl
.br
minfree:0
.br
naflags:fc,fd,fw,fm
naflags:fc,fd,fw,fm,cl
.br
policy:cnt
.br
... ...
This diff is collapsed. Click to expand it.
... ... @@ -18,7 +18,7 @@
*/
extern int bsm_init(ctx_t *ctx_p);
extern int bsm_wait(struct ctx *ctx_p, struct timeval *tv_p);
extern int bsm_wait(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *tv_p);
extern int bsm_handle(struct ctx *ctx_p, struct indexes *indexes_p);
extern int bsm_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath);
extern int bsm_deinit(ctx_t *ctx_p);
... ...
... ... @@ -22,14 +22,55 @@
#include "error.h"
#include "sync.h"
#include "indexes.h"
#include "inotify.h"
#include "mon_inotify.h"
enum event_bits {
UEM_DIR = 0x01,
UEM_CREATED = 0x02,
UEM_DELETED = 0x04,
};
struct recognize_event_return {
union {
struct {
eventobjtype_t objtype_old:16;
eventobjtype_t objtype_new:16;
} v;
uint32_t i;
} u;
};
static inline uint32_t recognize_event(uint32_t event) {
struct recognize_event_return r = {0};
eventobjtype_t type;
int is_created;
int is_deleted;
type = (event & IN_ISDIR ? EOT_DIR : EOT_FILE);
is_created = event & (IN_CREATE|IN_MOVED_TO);
is_deleted = event & (IN_DELETE_SELF|IN_DELETE|IN_MOVED_FROM);
debug(4, "type == %x; is_created == %x; is_deleted == %x", type, is_created, is_deleted);
r.u.v.objtype_old = type;
r.u.v.objtype_new = type;
if (is_created)
r.u.v.objtype_old = EOT_DOESNTEXIST;
if (is_deleted)
r.u.v.objtype_new = EOT_DOESNTEXIST;
return r.u.i;
}
int inotify_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath) {
int inotify_d = (int)(long)ctx_p->fsmondata;
return inotify_add_watch(inotify_d, accpath, INOTIFY_MARKMASK);
}
int inotify_wait(ctx_t *ctx_p, struct timeval *tv_p) {
int inotify_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p) {
int inotify_d = (int)(long)ctx_p->fsmondata;
debug(3, "select with timeout %li secs.", tv_p->tv_sec);
... ... @@ -126,7 +167,10 @@ int inotify_handle(ctx_t *ctx_p, indexes_t *indexes_p) {
st_size = lstat.st_size;
}
if (sync_prequeue_loadmark(1, ctx_p, indexes_p, path_full, NULL, event->mask, event->wd, st_mode, st_size, &path_rel, &path_rel_len, NULL)) {
struct recognize_event_return r;
r.u.i = recognize_event(event->mask);
if (sync_prequeue_loadmark(1, ctx_p, indexes_p, path_full, NULL, r.u.v.objtype_old, r.u.v.objtype_new, event->mask, event->wd, st_mode, st_size, &path_rel, &path_rel_len, NULL)) {
count = -1;
goto l_inotify_handle_end;
}
... ...
... ... @@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
extern int inotify_wait(struct ctx *ctx_p, struct timeval *tv_p);
extern int inotify_wait(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *tv_p);
extern int inotify_handle(struct ctx *ctx_p, struct indexes *indexes_p);
extern int inotify_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath);
extern int inotify_deinit(ctx_t *ctx_p);
... ...
... ... @@ -27,7 +27,7 @@
#include "indexes.h"
#include "fileutils.h"
#include "calc.h"
#include "kqueue.h"
#include "mon_kqueue.h"
struct monobj {
ino_t inode;
... ... @@ -54,6 +54,41 @@ struct kqueue_data {
void *fd_btree;
};
struct recognize_event_return {
union {
struct {
eventobjtype_t objtype_old:16;
eventobjtype_t objtype_new:16;
} v;
uint32_t i;
} u;
};
static inline uint32_t recognize_event(uint32_t event) {
struct recognize_event_return r = {{{0}}};
eventobjtype_t type;
int is_created;
int is_deleted;
type = (event & IN_ISDIR ? EOT_DIR : EOT_FILE);
is_created = event & (IN_CREATE|IN_MOVED_TO);
is_deleted = event & (IN_DELETE_SELF|IN_DELETE|IN_MOVED_FROM);
debug(4, "type == %x; is_created == %x; is_deleted == %x", type, is_created, is_deleted);
r.u.v.objtype_old = type;
r.u.v.objtype_new = type;
if (is_created)
r.u.v.objtype_old = EOT_DOESNTEXIST;
if (is_deleted)
r.u.v.objtype_new = EOT_DOESNTEXIST;
return r.u.i;
}
int kqueue_init(ctx_t *ctx_p) {
ctx_p->fsmondata = xcalloc(1, sizeof(struct kqueue_data));
if (ctx_p->fsmondata == NULL)
... ... @@ -317,7 +352,7 @@ int kqueue_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const a
return dir_obj_p->fd;
}
int kqueue_wait(ctx_t *ctx_p, struct timeval *tv_p) {
int kqueue_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p) {
struct kqueue_data *dat = ctx_p->fsmondata;
struct timespec ts;
... ... @@ -396,7 +431,10 @@ int kqueue_sync(ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_
{
char *path_rel = NULL;
size_t path_rel_len = 0;
int ret = sync_prequeue_loadmark(1, ctx_p, indexes_p, path_full, NULL, ev_p->fflags, ev_p->ident, st_mode, st_size, &path_rel, &path_rel_len, NULL);
struct recognize_event_return r;
r.u.i = recognize_event(ev_p->fflags);
int ret = sync_prequeue_loadmark(1, ctx_p, indexes_p, path_full, NULL, r.u.v.objtype_old, r.u.v.objtype_new, ev_p->fflags, ev_p->ident, st_mode, st_size, &path_rel, &path_rel_len, NULL);
if (path_rel != NULL)
free(path_rel);
... ... @@ -503,7 +541,7 @@ int kqueue_handle(ctx_t *ctx_p, indexes_t *indexes_p) {
sync_prequeue_unload(ctx_p, indexes_p);
dat->eventlist_count = 0;
} while (kqueue_wait(ctx_p, &tv));
} while (kqueue_wait(ctx_p, indexes_p, &tv));
return count;
}
... ...
... ... @@ -41,7 +41,7 @@
extern int kqueue_init();
extern int kqueue_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath);
extern int kqueue_wait(struct ctx *ctx_p, struct timeval *tv_p);
extern int kqueue_wait(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *tv_p);
extern int kqueue_handle(struct ctx *ctx_p, struct indexes *indexes_p);
extern int kqueue_deinit(ctx_t *ctx_p);
... ...
... ... @@ -32,6 +32,7 @@
#endif
#if BSM_SUPPORT
# include "mon_bsm.h"
# include <bsm/audit_kevents.h>
#endif
#include "main.h"
... ... @@ -74,14 +75,26 @@ gpointer eidup(gpointer ei_gp) {
return (gpointer)ei_dup;
}
static inline void evinfo_merge(eventinfo_t *evinfo_dst, eventinfo_t *evinfo_src) {
static inline void evinfo_merge(ctx_t *ctx_p, eventinfo_t *evinfo_dst, eventinfo_t *evinfo_src) {
debug(3, "evinfo_dst: seqid_min == %u; seqid_max == %u; objtype_old == %i; objtype_new == %i; \t"
"evinfo_src: seqid_min == %u; seqid_max == %u; objtype_old == %i; objtype_new == %i",
evinfo_dst->seqid_min, evinfo_dst->seqid_max, evinfo_dst->objtype_old, evinfo_dst->objtype_new,
evinfo_src->seqid_min, evinfo_src->seqid_max, evinfo_src->objtype_old, evinfo_src->objtype_new
);
evinfo_dst->evmask |= evinfo_src->evmask;
#if KQUEUE_SUPPORT | INOTIFY_SUPPORT
switch(ctx_p->flags[MONITOR]) {
#ifdef KQUEUE_SUPPORT
case NE_KQUEUE:
#endif
#ifdef INOTIFY_SUPPORT
case NE_INOTIFY:
#endif
evinfo_dst->evmask |= evinfo_src->evmask;
break;
}
#endif
evinfo_dst->flags |= evinfo_src->flags;
if(SEQID_LE(evinfo_src->seqid_min, evinfo_dst->seqid_min)) {
... ... @@ -92,6 +105,13 @@ static inline void evinfo_merge(eventinfo_t *evinfo_dst, eventinfo_t *evinfo_src
if(SEQID_GE(evinfo_src->seqid_max, evinfo_dst->seqid_max)) {
evinfo_dst->objtype_new = evinfo_src->objtype_new;
evinfo_dst->seqid_max = evinfo_src->seqid_max;
#ifdef BSM_SUPPORT
switch(ctx_p->flags[MONITOR]) {
case NE_BSM:
evinfo_dst->evmask = evinfo_src->evmask;
break;
}
#endif
}
return;
... ... @@ -1176,12 +1196,50 @@ static int sync_queuesync(const char *fpath_rel, eventinfo_t *evinfo, ctx_t *ctx
memcpy(evinfo_dup, evinfo, sizeof(*evinfo_dup));
return indexes_queueevent(indexes_p, strdup(fpath_rel), evinfo_dup, queue_id);
} else {
evinfo_merge(evinfo_q, evinfo);
evinfo_merge(ctx_p, evinfo_q, evinfo);
}
return 0;
}
static inline void evinfo_initialevmask(ctx_t *ctx_p, eventinfo_t *evinfo_p, int isdir) {
switch(ctx_p->flags[MONITOR]) {
#ifdef FANOTIFY_SUPPORT
case NE_FANOTIFY:
break;
#endif
#if INOTIFY_SUPPORT | KQUEUE_SUPPORT
#ifdef INOTIFY_SUPPORT
case NE_INOTIFY:
#endif
#ifdef KQUEUE_SUPPORT
case NE_KQUEUE:
#endif
evinfo_p->evmask = IN_CREATE_SELF;
if (isdir)
evinfo_p->evmask |= IN_ISDIR;
break;
#endif
#ifdef BSM_SUPPORT
case NE_BSM:
evinfo_p->evmask = (isdir ? AUE_MKDIR : AUE_OPEN_RWC);
break;
#endif
#ifdef VERYPARANOID
default:
critical("Unknown monitor subsystem: %u", ctx_p->flags[MONITOR]);
#endif
}
return;
}
static inline void api_evinfo_initialevmask(ctx_t *ctx_p, api_eventinfo_t *evinfo_p, int isdir) {
eventinfo_t evinfo;
evinfo_initialevmask(ctx_p, &evinfo, isdir);
evinfo_p->evmask = evinfo.evmask;
return;
}
int sync_initialsync_walk(ctx_t *ctx_p, const char *dirpath, indexes_t *indexes_p, queue_id_t queue_id, initsync_t initsync) {
int ret = 0;
const char *rootpaths[] = {dirpath, NULL};
... ... @@ -1305,30 +1363,7 @@ int sync_initialsync_walk(ctx_t *ctx_p, const char *dirpath, indexes_t *indexes_
evinfo.objtype_old = EOT_DOESNTEXIST;
evinfo.objtype_new = node->fts_info==FTS_D ? EOT_DIR : EOT_FILE;
evinfo.fsize = fts_no_stat ? 0 : node->fts_statp->st_size;
switch(ctx_p->flags[MONITOR]) {
#ifdef FANOTIFY_SUPPORT
case NE_FANOTIFY:
break;
#endif
#ifdef INOTIFY_SUPPORT
case NE_INOTIFY:
#endif
#ifdef KQUEUE_SUPPORT
case NE_KQUEUE:
#endif
#ifdef BSM_SUPPORT
case NE_KQUEUE:
#endif
evinfo.evmask = IN_CREATE_SELF;
if(node->fts_info==FTS_D) {
evinfo.evmask |= IN_ISDIR;
}
break;
#ifdef VERYPARANOID
default:
critical("Unknown monitor subsystem: %u", ctx_p->flags[MONITOR]);
#endif
}
evinfo_initialevmask(ctx_p, &evinfo, node->fts_info==FTS_D);
if(!rsync_and_prefer_excludes) {
debug(3, "queueing \"%s\" (depth: %i) with int-flags %p", node->fts_path, node->fts_level, (void *)(unsigned long)evinfo.flags);
... ... @@ -1397,7 +1432,7 @@ int sync_initialsync(const char *path, ctx_t *ctx_p, indexes_t *indexes_p, inits
memset(ei, 0, sizeof(*ei));
#endif
ei->evmask = IN_CREATE|IN_ISDIR;
api_evinfo_initialevmask(ctx_p, ei, 1);
ei->flags = EVIF_RECURSIVELY;
ei->path_len = strlen(path);
ei->path = strdup(path);
... ... @@ -1691,42 +1726,6 @@ static int sync_dosync(const char *fpath, uint32_t evmask, ctx_t *ctx_p, indexes
return ret;
}
static inline uint8_t monsystems_unifyevmask(ctx_t *ctx_p, uint32_t event_mask) {
int is_dir=0, is_created=0, is_deleted=0;
debug(4, "ctx_p->flags[MONITOR] == %u", ctx_p->flags[MONITOR]);
switch (ctx_p->flags[MONITOR]) {
#ifdef INOTIFY_SUPPORT
case NE_INOTIFY:
#endif
#ifdef KQUEUE_SUPPORT
case NE_KQUEUE:
#endif
#ifdef BSM_SUPPORT
case NE_BSM:
#endif
is_dir = event_mask & IN_ISDIR;
is_created = event_mask & (IN_CREATE|IN_MOVED_TO);
is_deleted = event_mask & (IN_DELETE_SELF|IN_DELETE|IN_MOVED_FROM);
break;
#ifdef VERYPARANOID
default:
critical("Unsupported FS monitor subsystem");
#endif
}
is_dir = is_dir != 0;
is_created = is_created != 0;
is_deleted = is_deleted != 0;
debug(4, "is_dir == %x; is_created == %x; is_deleted == %x", is_dir, is_created, is_deleted);
return
(is_dir * UEM_DIR ) |
(is_created * UEM_CREATED ) |
(is_deleted * UEM_DELETED ) |
0;
}
int sync_prequeue_loadmark
(
int monitored,
... ... @@ -1737,6 +1736,9 @@ int sync_prequeue_loadmark
const char *path_full,
const char *path_rel,
eventobjtype_t objtype_old,
eventobjtype_t objtype_new,
uint32_t event_mask,
int event_wd,
mode_t st_mode,
... ... @@ -1780,11 +1782,9 @@ int sync_prequeue_loadmark
// Handling different cases
uint8_t event_mask_unified = monsystems_unifyevmask(ctx_p, event_mask);
int is_dir = event_mask_unified & UEM_DIR;
int is_created = event_mask_unified & UEM_CREATED;
int is_deleted = event_mask_unified & UEM_DELETED;
int is_dir = objtype_old == EOT_DIR || objtype_new == EOT_DIR;
int is_created = objtype_old == EOT_DOESNTEXIST;
int is_deleted = objtype_new == EOT_DOESNTEXIST;
debug(4, "is_dir == %x; is_created == %x; is_deleted == %x", is_dir, is_created, is_deleted);
... ... @@ -1841,17 +1841,32 @@ int sync_prequeue_loadmark
evinfo->wd = event_wd;
evinfo->seqid_min = sync_seqid();
evinfo->seqid_max = evinfo->seqid_min;
evinfo->objtype_old = is_created ? EOT_DOESNTEXIST :
(is_dir ? EOT_DIR :EOT_FILE);
evinfo->objtype_old = objtype_old;
isnew++;
debug(3, "new event: fsize == %i; wd == %i", evinfo->fsize, evinfo->wd);
} else {
evinfo->seqid_max = sync_seqid();
}
evinfo->evmask |= event_mask;
evinfo->objtype_new = is_deleted ? EOT_DOESNTEXIST :
(is_dir ? EOT_DIR : EOT_FILE);
switch(ctx_p->flags[MONITOR]) {
#ifdef KQUEUE_SUPPORT
case NE_KQUEUE:
#endif
#ifdef INOTIFY_SUPPORT
case NE_INOTIFY:
#endif
#if KQUEUE_SUPPORT | INOTIFY_SUPPORT
evinfo->evmask |= event_mask;
break;
#endif
#ifdef BSM_SUPPORT
case NE_BSM:
evinfo->evmask = event_mask;
break;
#endif
}
evinfo->objtype_new = objtype_new;
debug(2, "path_rel == \"%s\"; evinfo->objtype_old == %i; evinfo->objtype_new == %i; "
"evinfo->seqid_min == %u; evinfo->seqid_max == %u",
... ... @@ -1984,7 +1999,7 @@ void _sync_idle_dosync_collectedevents(gpointer fpath_gp, gpointer evinfo_gp, gp
evinfo_idx->seqid_min = evinfo->seqid_min;
evinfo_idx->seqid_max = evinfo->seqid_max;
} else
evinfo_merge(evinfo_idx, evinfo);
evinfo_merge(ctx_p, evinfo_idx, evinfo);
int _queue_id = 0;
... ... @@ -1996,7 +2011,7 @@ void _sync_idle_dosync_collectedevents(gpointer fpath_gp, gpointer evinfo_gp, gp
eventinfo_t *evinfo_q = indexes_lookupinqueue(indexes_p, fpath, _queue_id);
if(evinfo_q != NULL) {
evinfo_merge(evinfo_idx, evinfo_q);
evinfo_merge(ctx_p, evinfo_idx, evinfo_q);
indexes_removefromqueue(indexes_p, fpath, _queue_id);
if(!indexes_queuelen(indexes_p, _queue_id))
... ... @@ -2030,13 +2045,16 @@ gboolean sync_trylocked(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp)
struct trylocked_arg *data = arg_p->data;
if (!sync_islocked(fpath)) {
if (sync_prequeue_loadmark(0, ctx_p, indexes_p, NULL, fpath, evinfo->evmask, 0, 0, 0, &data->path_full, &data->path_full_len, evinfo)) {
if (sync_prequeue_loadmark(0, ctx_p, indexes_p, NULL, fpath,
evinfo->evmask,
evinfo->objtype_old,
evinfo->objtype_new,
0, 0, 0, &data->path_full, &data->path_full_len, evinfo)) {
critical("Cannot re-queue \"%s\" to be synced", fpath);
return FALSE;
}
return TRUE;
}
return FALSE;
}
... ... @@ -2802,7 +2820,7 @@ int notify_wait(ctx_t *ctx_p, indexes_t *indexes_p) {
pthread_mutex_lock(&threadsinfo_p->mutex[PTHREAD_MUTEX_SELECT]);
pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);
int ret = ctx_p->notifyenginefunct.wait(ctx_p, &tv);
int ret = ctx_p->notifyenginefunct.wait(ctx_p, indexes_p, &tv);
pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_SELECT]);
... ... @@ -3502,7 +3520,7 @@ int sync_run(ctx_t *ctx_p) {
break;
#endif
#ifdef BSM_SUPPORT
case NE_KQUEUE:
case NE_BSM:
ctx_p->notifyenginefunct.add_watch_dir = bsm_add_watch_dir;
ctx_p->notifyenginefunct.wait = bsm_wait;
ctx_p->notifyenginefunct.handle = bsm_handle;
... ...
... ... @@ -33,6 +33,9 @@ extern int sync_prequeue_loadmark
const char *path_full,
const char *path_rel,
eventobjtype_t objtype_old,
eventobjtype_t objtype_new,
uint32_t event_mask,
int event_wd,
mode_t st_mode,
... ...