[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Dazuko-devel] Patch for patch-dazuko-linux-2.6.26
From: |
Lino Sanfilippo |
Subject: |
[Dazuko-devel] Patch for patch-dazuko-linux-2.6.26 |
Date: |
Tue, 28 Oct 2008 14:25:51 +0100 |
User-agent: |
IceDove 1.5.0.14eol (X11/20080724) |
Dear John, dear Mailing list
I am one of the developers at Avira that are currently working on a new
version of the
unix antivir workstation/server software. While working with the dazuko
patch
for linux kernel 2.6.26 I realized that after registering 5 groups at
dazuko, dazuko returns an error (-EINTR) and no more group registration
is possible.
After looking at the dazuko kernel code, I saw that 5 registered groups
are the max. of
groups that are allowed to be registered at the same time and any
further group registration
results in an EINTR error returned by the "write" system call (btw. is
an EINTR really the best error code to indicate that no more groups can
be handled? The process receiving this error would expect that it indeed
has been interrupted by a signal. Looking at the man page for "write" I
saw there is an ENOSPC error for example, that IMHO would make more
sense for this kind of error).
I also saw that a group is never removed once it has been registered,
even if unregistering it via dazuko_unregister_daemon().
I fixed this by modifying the kernel code in a way that its cleaning up
the data structures at unregistration. For this reason I introduced
an additional counter in the struct slotlist that keeps track of daemons
that are registered at it. I also reimplemented the way of reference
counting for the slotlists to ensure that no slotlist is freed if still
in use by a process.
Beside this the patch also removes a bug in run_daemon_on_slotlist(): At
two places the code was waiting there uninterruptibly (what is almost
never a good idea), but handled the case of interruption. I changed
that uninterruptible waiting into an interruptible one.
I created a patch for the dazuko-linux-2.6.26 patch, so if you want to
test it, please patch the original dazuko-patch for kernel 2.6.26 before
compiling the kernel.
The patch is attached to this mail, I hope you'll find it useful.
After studying the kernel code it also seems to me that the group
registration code in dazuko_register_daemon() contains a possible race
condition:
Looking for a slotlist to register a group PLUS assigning the group to
it should be done atomic.
Otherwise in the (admittedly rare) case that two or more processes are
trying to register the same group, one process could assign the group
to a slotlist right after another one has figured out that this
group is not yet registered and thus trying to register it, too. The
result could be 2 or more slotlists being assigned to the same group.
Torsten Reinecke and I are also currently evaluating the dazukoFS. After
a first view the solution with a stackable filesystem looks promising.
We will keep you in the loop about our experiences with it.
Best regards,
Lino Sanfilippo
Geschäftsführender Gesellschafter: Tjark Auerbach
Sitz der Gesellschaft: Tettnang
Handelsregister: Amtsgericht Ulm, HRB 630992
ALLGEMEINE GESCHÄFTSBEDINGUNGEN
Es gelten unsere Allgemeinen Geschäftsbedingungen
(AGB). Sie finden sie in der jeweils gültigen Fassung
im Internet unter http://www.avira.de/agb
***************************************************
diff -ru origin/security/dazuko/dazuko_core.c new3/security/dazuko/dazuko_core.c
--- origin/security/dazuko/dazuko_core.c 2008-10-17 15:15:40.000000000
+0200
+++ new3/security/dazuko/dazuko_core.c 2008-10-28 09:56:14.000000000 +0100
@@ -1,4 +1,4 @@
-/* DazukoXP. Allow cross platform file access control for 3rd-party
applications.
+ /* DazukoXP. Allow cross platform file access control for 3rd-party
applications.
Written by John Ogness <address@hidden>
Copyright (c) 2002, 2003, 2004, 2005, 2006 H+BEDV Datentechnik GmbH
@@ -117,7 +117,7 @@
struct event_properties event_p;
struct file_properties file_p;
struct xp_mutex mutex;
- struct slot_list *slot_list;
+ struct slot_list *slot_list;
struct xp_queue wait_daemon_waiting_until_this_slot_not_READY;
struct xp_queue
wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING;
struct xp_queue wait_daemon_waiting_until_this_slot_not_DONE;
@@ -126,6 +126,14 @@
struct slot_list
{
+ int container_idx;
+ /* number of processes registered at this group */
+ int active_count;
+ /* indicates if this group is valid (if 0 this
+ struct is being freed soon) */
+ struct xp_atomic invalid;
+ /* number of processes that hold a reference to this
+ list */
struct xp_atomic use_count;
struct slot slots[NUM_SLOTS];
struct dazuko_path *incl_paths;
@@ -136,7 +144,7 @@
struct xp_rwlock lock_trusted_list;
struct trusted_container *trusted_list;
char set_trusted_list;
- struct xp_queue
wait_kernel_waiting_for_any_READY_slot_or_zero_use_count;
+ struct xp_queue
wait_kernel_waiting_for_any_READY_slot_or_invalid;
};
struct slot_list_container
@@ -163,6 +171,7 @@
{
struct slot *slot;
struct slot_list *slotlist;
+ int invalid;
};
static int unique_count = 1;
@@ -173,6 +182,74 @@
static unsigned char
access_mask_cache[NUM_EVENTS][NUM_SLOT_LISTS];
static struct xp_mutex mutex_amc;
+// forward declarations
+static void dazuko_remove_all_paths(struct slot_list *slist);
+static inline void dazuko_remove_all_trusted(struct slot_list *sl);
+
+static void free_slot_list(struct slot_list *sl)
+{
+ int i;
+
+
+ dazuko_remove_all_paths(sl);
+
+ if (call_xp_atomic_read(&sl->use_count))
+ call_xp_print("dazuko: slot_list count was not 0 (possible
bug)\n");
+
+ for (i = 0 ; i < NUM_SLOTS; i++) {
+ call_xp_destroy_mutex(&sl->slots[i].mutex);
+
call_xp_destroy_queue(&sl->slots[i].wait_daemon_waiting_until_this_slot_not_READY);
+
call_xp_destroy_queue(&sl->slots[i].wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING);
+
call_xp_destroy_queue(&sl->slots[i].wait_daemon_waiting_until_this_slot_not_DONE);
+ }
+ call_xp_destroy_rwlock(&sl->lock_lists);
+ dazuko_remove_all_trusted(sl);
+ call_xp_destroy_rwlock(&sl->lock_trusted_list);
+
call_xp_destroy_queue(&sl->wait_kernel_waiting_for_any_READY_slot_or_invalid);
+
+ call_xp_free(sl->reg_name);
+ call_xp_free(sl);
+}
+
+
+static struct slot_list *get_slotlist(int slnum)
+{
+ struct slot_list *sl;
+
+ call_xp_down(&slot_lists[slnum].mutex);
+ sl = slot_lists[slnum].slot_list;
+ if (sl)
+ call_xp_atomic_inc(&sl->use_count);
+ call_xp_up(&slot_lists[slnum].mutex);
+
+ return sl;
+}
+
+
+
+static void release_slotlist(struct slot_list *sl)
+{
+ if (sl == NULL) {
+ printk(KERN_WARNING "%s: WARNING release on NULL slotlist\n",
__func__);
+ return;
+ }
+ /* we "abuse" the mutex of the slots old container idx,
+ since decrementing and testing usage counter must be
+ atomic. TODO: replace with dec_and_test() as soon
+ as available */
+ call_xp_down(&slot_lists[sl->container_idx].mutex);
+ call_xp_atomic_dec(&sl->use_count);
+ if (call_xp_atomic_read(&sl->use_count) == 0){
+ free_slot_list(sl);
+ }
+ call_xp_up(&slot_lists[sl->container_idx].mutex);
+}
+
+
+void dazuko_release_slotlist(struct slot_list *sl)
+{
+ release_slotlist(sl);
+}
int dazuko_vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
@@ -383,13 +460,7 @@
for (j=0 ; j<NUM_SLOT_LISTS ; j++)
{
-/* DOWN */
- call_xp_down(&(slot_lists[j].mutex));
-
- sl = slot_lists[j].slot_list;
-
- call_xp_up(&(slot_lists[j].mutex));
-/* UP */
+ sl = get_slotlist(j);
if (sl == NULL)
continue;
@@ -400,18 +471,21 @@
/* this is a special case since
ON_CLOSE_MODIFIED
* also triggers ON_CLOSE events */
- if (((DAZUKO_ON_CLOSE |
DAZUKO_ON_CLOSE_MODIFIED) & (sl->access_mask)) == 0)
+ if (((DAZUKO_ON_CLOSE |
DAZUKO_ON_CLOSE_MODIFIED) & (sl->access_mask)) == 0) {
+ release_slotlist(sl);
continue;
+ }
break;
default:
- if ((event & (sl->access_mask)) == 0)
+ if ((event & (sl->access_mask)) == 0) {
+ release_slotlist(sl);
continue;
+ }
break;
}
-
+ release_slotlist(sl);
/* if we made it this far, then the
* event is in the access mask */
-
access_mask_cache[i][index] = j;
index++;
}
@@ -515,7 +589,7 @@
return success;
}
-static struct slot * _dazuko_find_slot(struct daemon_id *did, int release,
struct slot_list *sl)
+static struct slot * _dazuko_find_slot(struct daemon_id *did, struct slot_list
*sl, int release)
{
/* Find the first slot with the same given
* pid number. SMP safe. Use this function
@@ -584,49 +658,45 @@
return NULL;
}
-static struct slot * dazuko_find_slot_and_slotlist(struct daemon_id *did, int
release, struct slot_list *slist, struct slot_list **sl_result)
+
+/* returns a free slot from a given slotlist if slist != NULL or from an
arbitrary slotlist
+ if slotlist == NULL. On successful return slist is filled with a valid
pointer to a slotlist
+ and the use counter for this slotlist has been incremented, thus the caller
must decrement
+ the slotlists use count by calling release_slotlist as soon as it does not
longer need it.
+ Returns a slot on success or NULL on failure.
+*/
+static struct slot *dazuko_find_slot_and_slotlist(struct daemon_id *did,
+ struct slot_list **slist,
+ int release)
{
struct slot *s;
int i;
struct slot_list *sl;
-
- if (slist == NULL)
- {
- for (i=0 ; i<NUM_SLOT_LISTS ; i++)
- {
-/* DOWN */
- call_xp_down(&(slot_lists[i].mutex));
-
- sl = slot_lists[i].slot_list;
-
- call_xp_up(&(slot_lists[i].mutex));
-/* UP */
-
- if (sl != NULL)
- {
- s = _dazuko_find_slot(did, release, sl);
- if (s != NULL)
- {
- /* set the current slot_list */
- if (sl_result != NULL)
- *sl_result = sl;
+
+ if (!*slist) {
+ for (i = 0; i < NUM_SLOT_LISTS; i++) {
+ sl = get_slotlist(i);
+
+ if (sl) {
+ s = _dazuko_find_slot(did, sl, release);
+ if (s) {
+ *slist = sl;
return s;
}
+ release_slotlist(sl);
}
}
- }
- else
- {
- return _dazuko_find_slot(did, release, slist);
- }
-
+ } else
+ return _dazuko_find_slot(did, *slist, release);
+
return NULL;
}
-static inline struct slot * dazuko_find_slot(struct daemon_id *did, int
release, struct slot_list *slist)
+
+static inline struct slot * dazuko_find_slot(struct daemon_id *did, struct
slot_list **slist, int release)
{
- return dazuko_find_slot_and_slotlist(did, release, slist, NULL);
+ return dazuko_find_slot_and_slotlist(did, slist, release);
}
static int dazuko_insert_path_fs(struct dazuko_path **list, struct xp_rwlock
*lock_lists, char *fs_path, int fs_len)
@@ -768,14 +838,15 @@
* current process id, the daemon. */
struct slot *s;
- struct slot_list *sl;
+ struct slot_list *sl = NULL;
+ int slot_invalid = 0;
DPRINT(("dazuko: dazuko_unregister_daemon() [%d]\n", did->unique));
/* find our slot and hold the mutex
* if we find it */
/* DOWN? */
- s = dazuko_find_slot_and_slotlist(did, 0, NULL, &sl);
+ s = dazuko_find_slot_and_slotlist(did, &sl, 0);
if (s == NULL)
{
@@ -800,21 +871,6 @@
call_xp_up(&(s->mutex));
/* UP */
- call_xp_atomic_dec(&(sl->use_count));
-
- /* Remove all the include and exclude paths
- * if there are no more daemons in this group */
-
- if (call_xp_atomic_read(&(sl->use_count)) == 0)
- {
- sl->access_mask = 0;
- dazuko_setup_amc_cache();
- dazuko_remove_all_paths(sl);
-
- /* this was the last daemon in the group */
- call_xp_atomic_dec(&groupcount);
- }
-
/* active should always be positive here, but
* let's check just to be sure. ;) */
if (call_xp_atomic_read(&active) > 0)
@@ -830,16 +886,37 @@
call_xp_print("dazuko: active count error (possible bug)\n");
}
- /* slot->state has changed to FREE, notifiy appropriate queues */
+
+ /* slot->state has changed to FREE, notify appropriate queues */
/* we need to notify all slot queues because unique could be -1,
* which means that it is possible that this process does not
* really belong to this slot */
call_xp_notify(&(s->wait_daemon_waiting_until_this_slot_not_DONE));
call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
call_xp_notify(&(s->wait_daemon_waiting_until_this_slot_not_READY));
+
+ call_xp_down(&slot_lists[sl->container_idx].mutex);
- /* slotlist->use_count has been decreased, notify appropriate queue */
-
call_xp_notify(&(sl->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
+ sl->active_count--;
+ /* check if this was the last daemon in the group,
+ and if slotlist has to bee freed */
+ if (sl->active_count == 0) {
+ /* unlink this list from slotlists container */
+ call_xp_atomic_dec(&sl->use_count);
+ slot_lists[sl->container_idx].slot_list = NULL;
+ call_xp_atomic_set(&sl->invalid, 1);
+ call_xp_atomic_dec(&groupcount);
+ slot_invalid = 1;
+ }
+ call_xp_up(&slot_lists[sl->container_idx].mutex);
+
+ /* notify appropriate queue about slotlist state change */
+ call_xp_notify(&sl->wait_kernel_waiting_for_any_READY_slot_or_invalid);
+
+ if (slot_invalid) /*slotlist has been freed */
+ dazuko_setup_amc_cache();
+
+ release_slotlist(sl);
return 0;
}
@@ -871,13 +948,7 @@
for (i=0 ; i<NUM_SLOT_LISTS ; i++)
{
-/* DOWN */
- call_xp_down(&(slot_lists[i].mutex));
-
- sl = slot_lists[i].slot_list;
-
- call_xp_up(&(slot_lists[i].mutex));
-/* UP */
+ sl = get_slotlist(i);
if (sl != NULL)
{
@@ -895,6 +966,8 @@
if (*p1 == *p2)
return sl;
+
+ release_slotlist(sl);
}
}
@@ -906,113 +979,110 @@
const char *p1;
char *p2;
struct slot *s;
- struct slot_list *sl;
- int i;
+ struct slot_list *sl = NULL;
DPRINT(("dazuko: dazuko_register_daemon() [%d]\n", did->unique));
if (did == NULL || reg_name == NULL)
return XP_ERROR_PERMISSION;
- s = dazuko_find_slot(did, 1, NULL);
+ s = dazuko_find_slot(did, &sl, 1);
if (s != NULL)
{
/* We are already registered! */
call_xp_print("dazuko: daemon %d already assigned to
slot[%d]\n", did->unique, s->id);
-
+ release_slotlist(sl);
return XP_ERROR_PERMISSION;
}
/* Find the slot_list with the matching name. */
+ /* FIXME:
+ Checking for a free slotlist by groupname AND assigning
+ a group to a free slotlist should be done atomic to avoid
+ possible race conditions if two or more processes try to register
+ a group with the same name at the same time */
sl = find_slot_list_from_groupname(reg_name);
- if (sl == NULL)
- {
+ if (sl == NULL) {
+ int i;
/* There is no slot_list with this name. We
* need to make one. */
- sl = (struct slot_list *)call_xp_malloc(sizeof(struct
slot_list));
- if (sl == NULL)
- return XP_ERROR_FAULT;
-
- dazuko_bzero(sl, sizeof(struct slot_list));
-
- sl->reg_name = call_xp_malloc(string_length + 1);
- if (sl->reg_name == NULL)
- {
- call_xp_free(sl);
- return XP_ERROR_FAULT;
- }
- dazuko_bzero(sl->reg_name, string_length + 1);
-
- call_xp_atomic_set(&(sl->use_count), 0);
- call_xp_init_rwlock(&(sl->lock_lists));
- call_xp_init_rwlock(&(sl->lock_trusted_list));
-
call_xp_init_queue(&(sl->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
-
- p1 = reg_name;
- p2 = sl->reg_name;
-
- while (*p1)
- {
- *p2 = *p1;
-
- p1++;
- p2++;
- }
- *p2 = 0;
-
- /* give each slot a unique id and assign slot_list */
- for (i=0 ; i<NUM_SLOTS ; i++)
- {
- sl->slots[i].id = i;
- sl->slots[i].slot_list = sl;
- call_xp_init_mutex(&(sl->slots[i].mutex));
-
call_xp_init_queue(&(sl->slots[i].wait_daemon_waiting_until_this_slot_not_READY));
-
call_xp_init_queue(&(sl->slots[i].wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
-
call_xp_init_queue(&(sl->slots[i].wait_daemon_waiting_until_this_slot_not_DONE));
- }
-
/* we need to find an empty slot */
- for (i=0 ; i<NUM_SLOT_LISTS ; i++)
- {
-/* DOWN */
- call_xp_down(&(slot_lists[i].mutex));
-
- if (slot_lists[i].slot_list == NULL)
- {
+ for (i=0 ; (i < NUM_SLOT_LISTS) && !sl; i++) {
+ /* DOWN */
+ call_xp_down(&slot_lists[i].mutex);
+
+ if (slot_lists[i].slot_list == NULL) {
+ int j;
+
+ sl = (struct slot_list *)
+ call_xp_malloc(sizeof(struct
slot_list));
+ if (sl == NULL) {
+ call_xp_up(&slot_lists[i].mutex);
+ return XP_ERROR_FAULT;
+ }
+ dazuko_bzero(sl, sizeof(struct slot_list));
+
+ sl->container_idx = i;
+ sl->reg_name = call_xp_malloc(string_length +
1);
+ if (sl->reg_name == NULL) {
+ call_xp_free(sl);
+ call_xp_up(&slot_lists[i].mutex);
+ return XP_ERROR_FAULT;
+ }
+ dazuko_bzero(sl->reg_name, string_length + 1);
+
+ /* initial use count. If this ever reaches 0
the
+ slotlist will be freed */
+ call_xp_atomic_set(&sl->use_count, 1);
+ call_xp_atomic_set(&sl->invalid, 0);
+ call_xp_init_rwlock(&sl->lock_lists);
+ call_xp_init_rwlock(&sl->lock_trusted_list);
+
call_xp_init_queue(&sl->wait_kernel_waiting_for_any_READY_slot_or_invalid);
+
+ p1 = reg_name;
+ p2 = sl->reg_name;
+
+ while (*p1)
+ {
+ *p2 = *p1;
+
+ p1++;
+ p2++;
+ }
+ *p2 = 0;
+
+ /* give each slot a unique id and assign
slot_list */
+ for (j=0 ; j < NUM_SLOTS; j++)
+ {
+ sl->slots[j].id = j;
+ sl->slots[j].slot_list = sl;
+
call_xp_init_mutex(&(sl->slots[j].mutex));
+
call_xp_init_queue(&(sl->slots[j].wait_daemon_waiting_until_this_slot_not_READY));
+
call_xp_init_queue(&(sl->slots[j].wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
+
call_xp_init_queue(&(sl->slots[j].wait_daemon_waiting_until_this_slot_not_DONE));
+ }
slot_lists[i].slot_list = sl;
-
- call_xp_up(&(slot_lists[i].mutex));
-/* UP */
- break;
- }
-
- call_xp_up(&(slot_lists[i].mutex));
-/* UP */
+ }
+ /* UP */
+ call_xp_up(&slot_lists[i].mutex);
}
-
- if (i == NUM_SLOT_LISTS)
- {
- /* no empty slot :( */
-
- call_xp_free(sl->reg_name);
- call_xp_free(sl);
-
+ if (!sl)
return XP_ERROR_BUSY;
- }
}
-
/* find an available slot and hold the mutex
* if we find one */
/* DOWN? */
- s = dazuko_find_slot(NULL, 0, sl);
+ s = dazuko_find_slot(NULL, &sl, 0);
- if (s == NULL)
+ if (s == NULL) {
+ release_slotlist(sl);
return XP_ERROR_BUSY;
+ }
/* DOWN */
@@ -1023,21 +1093,28 @@
call_xp_atomic_inc(&active);
- /* get new unique id for this process */
+ /* get new unique id for this process */
did->unique = dazuko_get_new_unique();
s->did.unique = did->unique;
s->did.xp_id = call_xp_id_copy(did->xp_id);
s->write_mode = write_mode;
- call_xp_atomic_inc(&(sl->use_count));
-
- if (call_xp_atomic_read(&(sl->use_count)) == 1)
- {
+
+ call_xp_down(&slot_lists[sl->container_idx].mutex);
+ sl->active_count++;
+
+ if (sl->active_count == 1) /* first usage */
+ {
+ /* inc use count again, since it will
+ * be decreased below */
+ call_xp_atomic_inc(&sl->use_count);
/* this is the first daemon in the group */
call_xp_atomic_inc(&groupcount);
}
+ call_xp_up(&slot_lists[sl->container_idx].mutex);
+
/* the daemon is registered, but not yet
* ready to receive files */
__dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE);
@@ -1047,13 +1124,15 @@
call_xp_up(&(s->mutex));
/* UP */
+ release_slotlist(sl);
+
/* although there was a state change, we don't need to notify any queues
* because a new slot is first interesting when it hits the READY state
*/
return 0;
}
-static struct slot* dazuko_get_an_access(struct daemon_id *did)
+static struct slot* dazuko_get_an_access(struct daemon_id *did, struct
slot_list **psl)
{
/* The daemon is requesting a filename of a file
* to scan. This code will wait until a filename
@@ -1069,7 +1148,8 @@
tryagain:
/* find our slot */
- s = dazuko_find_slot(did, 1, NULL);
+ *psl = NULL;
+ s = dazuko_find_slot(did, psl, 1);
if (s == NULL)
{
@@ -1080,7 +1160,7 @@
return NULL;
}
- s = dazuko_find_slot(did, 1, NULL);
+ s = dazuko_find_slot(did, psl, 1);
if (s == NULL)
{
call_xp_print("dazuko: unregistered daemon %d attempted
to get access\n", did->unique);
@@ -1106,7 +1186,7 @@
}
/* slot->state has changed to READY, notify appropriate queue */
-
call_xp_notify(&(s->slot_list->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
+
call_xp_notify(&(s->slot_list->wait_kernel_waiting_for_any_READY_slot_or_invalid));
cond_p.slot = s;
cond_p.state = DAZUKO_READY;
@@ -1123,7 +1203,7 @@
/* slot->state has changed to BROKEN, notifiy
appropriate queue */
call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
}
-
+ release_slotlist(*psl);
return NULL;
}
@@ -1136,7 +1216,7 @@
if (!dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_WORKING, 0))
{
/* State transition error. Try again., */
-
+ release_slotlist(*psl);
goto tryagain;
}
@@ -1152,15 +1232,20 @@
static int dazuko_initialize_cache(struct daemon_id *did, unsigned long ttl)
{
+ int rv;
+ struct slot_list *sl = NULL;
/* find our slot */
- if (dazuko_find_slot(did, 1, NULL) == NULL)
+
+ if (dazuko_find_slot(did, &sl, 1) == NULL)
{
/* this daemon is not registered! */
return -1;
}
+ rv = call_xp_init_cache(ttl);
- return call_xp_init_cache(ttl);
+ release_slotlist(sl);
+ return rv;
}
static int dazuko_return_access(struct daemon_id *did, int response, struct
slot *s)
@@ -1533,7 +1618,7 @@
* option in the kernel. */
struct slot *s;
- struct slot_list *sl;
+ struct slot_list *sl = NULL;
int error = 0;
/* sanity check */
@@ -1544,12 +1629,15 @@
* (or that we don't register twice) */
/* find our slot */
- s = dazuko_find_slot_and_slotlist(did, 1, NULL, &sl);
+ s = dazuko_find_slot_and_slotlist(did, &sl, 1);
switch (opt)
{
case REGISTER:
call_xp_print("dazuko: dazuko_set_option does not
support REGISTER (bug!)\n");
+ if (sl)
+ release_slotlist(sl);
+
return XP_ERROR_PERMISSION;
case UNREGISTER:
@@ -1571,7 +1659,7 @@
return XP_ERROR_PERMISSION;
}
- s = dazuko_find_slot_and_slotlist(did, 1, NULL,
&sl);
+ s = dazuko_find_slot_and_slotlist(did, &sl, 1);
if (s == NULL)
{
call_xp_print("dazuko: unregistered
daemon %d attempted access\n", did->unique);
@@ -1631,6 +1719,7 @@
error = XP_ERROR_INVALID;
break;
}
+ release_slotlist(sl);
return error;
}
@@ -1664,12 +1753,17 @@
return NULL;
}
-static int get_ready_slot_condition(void *param)
+static int get_ready_slot_condition(void *p)
{
- return ((((struct get_ready_slot_condition_param *)param)->slot =
dazuko_get_and_hold_ready_slot(((struct get_ready_slot_condition_param
*)param)->slotlist)) != NULL
- || call_xp_atomic_read(&(((struct
get_ready_slot_condition_param *)param)->slotlist->use_count)) == 0);
+ struct get_ready_slot_condition_param *param = p;
+
+ param->slot = dazuko_get_and_hold_ready_slot(param->slotlist);
+ param->invalid = call_xp_atomic_read(¶m->slotlist->invalid) ? 1 :
0;
+
+ return !!param->slot || param->invalid;
}
+
static int dazuko_run_daemon_on_slotlist(unsigned long event, char *filename,
int filenamelength, struct event_properties *event_p, struct file_properties
*file_p, int prev_response, struct slot_list *sl, struct dazuko_file_struct
*dfs)
{
/* This is the main function called by the kernel
@@ -1691,7 +1785,7 @@
/* wait for a slot to become ready */
cond_p1.slotlist = sl;
cond_p1.slot = s;
- if
(call_xp_wait_until_condition(&(sl->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count),
get_ready_slot_condition, &cond_p1, 0) != 0)
+ if
(call_xp_wait_until_condition(&(sl->wait_kernel_waiting_for_any_READY_slot_or_invalid),
get_ready_slot_condition, &cond_p1, 1) != 0)
{
/* The kernel process was killed while
* waiting for a slot to become ready.
@@ -1702,6 +1796,9 @@
return -1; /* user interrupted */
}
+ if (cond_p1.invalid)
+ return -1;
+
/* Make sure we have a slot. We may have
* gotten past the last wait because we
* are no longer active. */
@@ -1757,7 +1854,8 @@
cond_p2.state1 = DAZUKO_WAITING;
cond_p2.slot2 = s;
cond_p2.state2 = DAZUKO_WORKING;
- if
(call_xp_wait_until_condition(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING),
two_slot_state_not_condition, &cond_p2, 0) != 0)
+
+ if
(call_xp_wait_until_condition(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING),
two_slot_state_not_condition, &cond_p2, 1) != 0)
{
/* The kernel process was killed while
* waiting for a daemon to process the file.
@@ -1775,7 +1873,6 @@
return -1; /* user interrupted */
}
-
/* we are working with the slot, so
* we need to lock it */
/* DOWN */
@@ -1972,24 +2069,18 @@
call_xp_print("dazuko: illegal value:%d in
access_mask_cache (possible bug)\n", j);
break;
}
-
-/* DOWN */
- call_xp_down(&(slot_lists[j].mutex));
-
- sl = slot_lists[j].slot_list;
-
- call_xp_up(&(slot_lists[j].mutex));
-/* UP */
-
+ sl = get_slotlist(j);
if (sl == NULL)
continue;
-
- if (sl == skip_slotlist)
+ if (sl == skip_slotlist) {
+ release_slotlist(sl);
continue;
-
+ }
#ifdef ANONYMOUS_RESOLVE
- if (!dazuko_should_scan(dfs, sl))
+ if (!dazuko_should_scan(dfs, sl)) {
+ release_slotlist(sl);
continue;
+ }
error = dazuko_run_daemon_on_slotlist(event, dfs->filename,
dfs->filename_length, event_p, &(dfs->file_p), rc, sl, NULL);
#else
@@ -2000,6 +2091,7 @@
{
/* most likely user interrupt */
rc = error;
+ release_slotlist(sl);
break;
}
else if (error > 0)
@@ -2007,6 +2099,7 @@
/* this daemon wants access blocked */
rc = 1;
}
+ release_slotlist(sl);
}
return rc;
@@ -2034,7 +2127,7 @@
return next;
}
-inline int dazuko_is_our_daemon(struct xp_daemon_id *xp_id, struct slot_list
**slotlist, struct slot **slot)
+inline int dazuko_is_our_daemon(struct xp_daemon_id *xp_id, struct slot_list
**slotlist)
{
/* Check if the current process is one
* of the daemons. */
@@ -2053,39 +2146,31 @@
for (i=0 ; i<NUM_SLOT_LISTS ; i++)
{
-/* DOWN */
- call_xp_down(&(slot_lists[i].mutex));
-
- sl = slot_lists[i].slot_list;
-
- call_xp_up(&(slot_lists[i].mutex));
-/* UP */
-
- if (sl == NULL)
+ sl = get_slotlist(i);
+ if (sl== NULL)
continue;
- s = _dazuko_find_slot(&did, 1, sl);
+ s = _dazuko_find_slot(&did, sl, 1);
if (s != NULL)
{
ret = 1;
- if (slotlist != NULL)
- *slotlist = sl;
-
- if (slot != NULL)
- *slot = s;
-
+ *slotlist = sl;
break;
}
- if (did.xp_id == NULL)
+ if (did.xp_id == NULL) {
+ release_slotlist(sl);
continue;
+ }
/* This boolean is not protected by a lock on purpose.
* It is used as optimization when there are no trusted
* processes. If it is set, then we will use the lock. */
- if (!(sl->set_trusted_list))
+ if (!(sl->set_trusted_list)) {
+ release_slotlist(sl);
continue;
+ }
/* LOCK */
call_xp_read_lock(&(sl->lock_trusted_list));
@@ -2093,15 +2178,16 @@
tc = sl->trusted_list;
prev = NULL;
while (tc != NULL)
- {
+ {
+
+
cmp = call_xp_id_compare(tc->xp_id, did.xp_id, 1);
if (cmp == DAZUKO_SAME || (cmp == DAZUKO_CHILD &&
tc->trust_children))
{
ret = 1;
- if (slotlist != NULL)
- *slotlist = sl;
+ *slotlist = sl;
break;
}
@@ -2119,12 +2205,12 @@
tc = tc->next;
}
}
-
+ /* UNLOCK */
call_xp_read_unlock(&(sl->lock_trusted_list));
-/* UNLOCK */
if (ret)
break;
+ release_slotlist(sl);
}
call_xp_id_free(did.xp_id);
@@ -2245,8 +2331,10 @@
return -1;
/* check if this group is accepting trust requests */
- if ((DAZUKO_TRUST_REQUEST & sl->access_mask) == 0)
+ if ((DAZUKO_TRUST_REQUEST & sl->access_mask) == 0) {
+ release_slotlist(sl);
return -1;
+ }
memset(&event_p, 0, sizeof(event_p));
@@ -2273,7 +2361,7 @@
rc = dazuko_add_trusted_daemon(xp_id, token, trust_children,
sl);
}
-
+ release_slotlist(sl);
return rc;
}
@@ -2287,22 +2375,17 @@
for (i=0 ; i<NUM_SLOT_LISTS ; i++)
{
-/* DOWN */
- call_xp_down(&(slot_lists[i].mutex));
-
- sl = slot_lists[i].slot_list;
-
- call_xp_up(&(slot_lists[i].mutex));
-/* UP */
-
+ sl = get_slotlist(i);
if (sl == NULL)
continue;
/* This boolean is not protected by a lock on purpose.
* It is used as optimization when there are no trusted
* processes. If it is set, then we will use the lock. */
- if (!(sl->set_trusted_list))
+ if (!(sl->set_trusted_list)) {
+ release_slotlist(sl);
continue;
+ }
/* LOCK */
call_xp_read_lock(&(sl->lock_trusted_list));
@@ -2329,6 +2412,7 @@
sl->set_trusted_list = 0;
call_xp_read_unlock(&(sl->lock_trusted_list));
+ release_slotlist(sl);
/* UNLOCK */
}
@@ -2490,6 +2574,7 @@
int error = 0;
struct slot *s;
struct daemon_id did;
+ struct slot_list *sl = NULL;
/* read "\nID=id" */
/* send "\nEV=event\nFN=file\nUI=uid\nPI=pid\nFL=flags\nMD=mode..." */
@@ -2511,7 +2596,8 @@
dazuko_handle_request_get_an_access_begin:
/* DOWN? */
- s = dazuko_get_an_access(&did);
+ sl = NULL;
+ s = dazuko_get_an_access(&did, &sl);
if (s == NULL)
{
@@ -2533,6 +2619,7 @@
call_xp_up(&(s->mutex));
/* UP */
dazuko_return_access(&did, 0, s);
+ release_slotlist(sl);
goto dazuko_handle_request_get_an_access_begin;
}
@@ -2543,6 +2630,7 @@
call_xp_up(&(s->mutex));
/* UP */
dazuko_return_access(&did, 0, s);
+ release_slotlist(sl);
goto dazuko_handle_request_get_an_access_begin;
}
@@ -2606,7 +2694,7 @@
call_xp_up(&(s->mutex));
/* UP */
}
-
+ release_slotlist(sl);
call_xp_id_free(did.xp_id);
return error;
@@ -2619,6 +2707,7 @@
int error = 0;
struct daemon_id did;
struct slot *s;
+ struct slot_list *sl = NULL;
/* read "\nID=id\nDN=deny" */
@@ -2638,7 +2727,7 @@
did.unique = dazuko_strtol(value1);
/* find our slot */
- s = dazuko_find_slot(&did, 1, NULL);
+ s = dazuko_find_slot(&did, &sl, 1);
if (s == NULL)
{
@@ -2653,6 +2742,7 @@
{
if (!handle_event_as_readonly(s))
error = dazuko_return_access(&did,
dazuko_strtoul(value2), s);
+ release_slotlist(sl);
}
call_xp_free(value1);
@@ -3118,7 +3208,6 @@
{
struct access_compat1 *user_request_1;
struct access_compat1 *temp_request_1;
- struct slot_list *sl;
int error = 0;
struct slot *s;
char *k_param;
@@ -3132,95 +3221,100 @@
did.xp_id = call_xp_id_copy(xp_id);
did.unique = -1;
- switch (cmd)
- {
- case IOCTL_GET_AN_ACCESS:
- /* The daemon is requesting a filename of a file
- * to scan. This code will wait until a filename
- * is available, or until we should be killed.
- * (killing is done if any errors occur as well
- * as when the user kills us) */
-
- user_request_1 = (struct access_compat1 *)ptr;
+ switch (cmd) {
+ case IOCTL_GET_AN_ACCESS: {
+ struct slot_list *sl = NULL;
+
+ /* The daemon is requesting a filename of a file
+ * to scan. This code will wait until a filename
+ * is available, or until we should be killed.
+ * (killing is done if any errors occur as well
+ * as when the user kills us) */
+
+ user_request_1 = (struct access_compat1 *)ptr;
+
+ error = call_xp_verify_user_writable(user_request_1,
sizeof(struct access_compat1));
+ if (error)
+ {
+ error = XP_ERROR_FAULT;
+ break;
+ }
+
+ /* DOWN? */
+ s = dazuko_get_an_access(&did, &sl);
+
+ if (s == NULL)
+ {
+ error = XP_ERROR_INTERRUPT;
+ break;
+ }
+
+ /* DOWN */
+
+ /* Slot IS in WORKING state. Copy all the
+ * necessary information to userspace structure. */
+
+ if (s->filenamelength >=
DAZUKO_FILENAME_MAX_LENGTH_COMPAT1)
+ {
+ /* filename length overflow :( */
+
+ s->filename[DAZUKO_FILENAME_MAX_LENGTH_COMPAT1
- 1] = 0;
+ temp_length =
DAZUKO_FILENAME_MAX_LENGTH_COMPAT1;
+ }
+ else
+ {
+ temp_length = s->filenamelength + 1;
+ }
+
+ temp_request_1 = (struct access_compat1
*)call_xp_malloc(sizeof(struct access_compat1));
+ if (temp_request_1 == NULL)
+ {
+ error = XP_ERROR_FAULT;
+ }
+ else if (call_xp_copyin(user_request_1,
temp_request_1, sizeof(struct access_compat1)) != 0)
+ {
+ error = XP_ERROR_FAULT;
+ }
+
+ if (error == 0)
+ {
+ temp_request_1->event = s->event;
+ temp_request_1->o_flags = s->event_p.flags;
+ temp_request_1->o_mode = s->event_p.mode;
+ temp_request_1->uid = s->event_p.uid;
+ temp_request_1->pid = s->event_p.pid;
+ memcpy(temp_request_1->filename, s->filename,
temp_length);
+
+ if (call_xp_copyout(temp_request_1,
user_request_1, sizeof(struct access_compat1)) != 0)
+ {
+ error = XP_ERROR_FAULT;
+ }
+ }
+
+ call_xp_up(&(s->mutex));
+ /* UP */
+
+
+ if (error)
+ {
+ if (dazuko_change_slot_state(s,
DAZUKO_WORKING, DAZUKO_BROKEN, 1))
+ {
+ /* slot->state has changed to BROKEN,
notifiy appropriate queue */
+
call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
+ }
+ }
+ release_slotlist(sl);
+
+ if (temp_request_1 != NULL)
+ {
+ call_xp_free(temp_request_1);
+ }
+ }
+ break;
+
+ case IOCTL_RETURN_ACCESS: {
+ struct slot_list *sl = NULL;
- error = call_xp_verify_user_writable(user_request_1,
sizeof(struct access_compat1));
- if (error)
- {
- error = XP_ERROR_FAULT;
- break;
- }
-
-/* DOWN? */
- s = dazuko_get_an_access(&did);
-
- if (s == NULL)
- {
- error = XP_ERROR_INTERRUPT;
- break;
- }
-
-/* DOWN */
-
- /* Slot IS in WORKING state. Copy all the
- * necessary information to userspace structure. */
-
- if (s->filenamelength >=
DAZUKO_FILENAME_MAX_LENGTH_COMPAT1)
- {
- /* filename length overflow :( */
-
- s->filename[DAZUKO_FILENAME_MAX_LENGTH_COMPAT1
- 1] = 0;
- temp_length =
DAZUKO_FILENAME_MAX_LENGTH_COMPAT1;
- }
- else
- {
- temp_length = s->filenamelength + 1;
- }
-
- temp_request_1 = (struct access_compat1
*)call_xp_malloc(sizeof(struct access_compat1));
- if (temp_request_1 == NULL)
- {
- error = XP_ERROR_FAULT;
- }
- else if (call_xp_copyin(user_request_1, temp_request_1,
sizeof(struct access_compat1)) != 0)
- {
- error = XP_ERROR_FAULT;
- }
-
- if (error == 0)
- {
- temp_request_1->event = s->event;
- temp_request_1->o_flags = s->event_p.flags;
- temp_request_1->o_mode = s->event_p.mode;
- temp_request_1->uid = s->event_p.uid;
- temp_request_1->pid = s->event_p.pid;
- memcpy(temp_request_1->filename, s->filename,
temp_length);
-
- if (call_xp_copyout(temp_request_1,
user_request_1, sizeof(struct access_compat1)) != 0)
- {
- error = XP_ERROR_FAULT;
- }
- }
-
- call_xp_up(&(s->mutex));
-/* UP */
-
- if (error)
- {
- if (dazuko_change_slot_state(s, DAZUKO_WORKING,
DAZUKO_BROKEN, 1))
- {
- /* slot->state has changed to BROKEN,
notifiy appropriate queue */
-
call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
- }
- }
-
- if (temp_request_1 != NULL)
- {
- call_xp_free(temp_request_1);
- }
-
- break;
-
- case IOCTL_RETURN_ACCESS:
/* The daemon has finished scanning a file
* and has the response to give. The daemon's
* slot should be in the WORKING state. */
@@ -3251,7 +3345,7 @@
call_xp_free(temp_request_1);
/* find our slot */
- s = dazuko_find_slot(&did, 1, NULL);
+ s = dazuko_find_slot(&did, &sl, 1);
if (s == NULL)
{
@@ -3265,7 +3359,9 @@
else if (!handle_event_as_readonly(s))
{
error = dazuko_return_access(&did, temp_int, s);
+ release_slotlist(sl);
}
+ }
break;
@@ -3330,34 +3426,31 @@
k_param[temp_length] = 0;
- switch (temp_int)
- {
- case REGISTER:
- error = dazuko_register_daemon(&did,
k_param, temp_length, 1);
- break;
-
- case SET_ACCESS_MASK:
- /* find our slot */
- if (dazuko_find_slot_and_slotlist(&did,
1, NULL, &sl) == NULL)
- {
- error = XP_ERROR_PERMISSION;
- }
- else if (sl == NULL)
- {
- error = XP_ERROR_PERMISSION;
- }
- else
- {
- sl->access_mask = k_param[0];
-
- /* rebuild access_mask_cache */
- dazuko_setup_amc_cache();
- }
- break;
+ switch (temp_int) {
+ case REGISTER:
+ error = dazuko_register_daemon(&did, k_param,
temp_length, 1);
+ break;
+
+ case SET_ACCESS_MASK: {
+ struct slot_list *sl = NULL;
+ /* find our slot */
+ if (dazuko_find_slot_and_slotlist(&did, &sl,
1) == NULL)
+ {
+ error = XP_ERROR_PERMISSION;
+ }
+ else
+ {
+ sl->access_mask = k_param[0];
+ release_slotlist(sl);
+ /* rebuild access_mask_cache */
+ dazuko_setup_amc_cache();
+ }
+ }
+ break;
- default:
- error = dazuko_set_option(&did,
temp_int, k_param, temp_length);
- break;
+ default:
+ error = dazuko_set_option(&did, temp_int,
k_param, temp_length);
+ break;
}
call_xp_free(k_param);
@@ -3375,6 +3468,8 @@
return error;
}
+/* NOTE: susccessful return does not guarantee that the passed slot_list
pointer contains
+ a valid address. This differs from most functions that take a slot_list
pointer address */
int dazuko_check_access(unsigned long event, int daemon_is_allowed, struct
xp_daemon_id *xp_id, struct slot_list **cached_lookup)
{
int i;
@@ -3401,30 +3496,28 @@
if (i == AMC_UNSET)
return -1;
- if (dazuko_is_our_daemon(xp_id, &sl, NULL))
+ if (dazuko_is_our_daemon(xp_id, &sl))
{
/* should daemons be allowed this event without a scan? */
if (daemon_is_allowed)
{
/* this is one of our daemons, so we will report as
* as if this event was not in the mask */
-
+ release_slotlist(sl);
return -1;
- }
+ }
else
{
/* this is one of our daemons, but the
* other groups must be informed */
/* if there are no other groups, allow this event */
- if (call_xp_atomic_read(&groupcount) == 1)
- return -1;
-
- if (cached_lookup != NULL)
- {
- /* this slot list (ours) will be skipped */
- *cached_lookup = sl;
- }
+ if (call_xp_atomic_read(&groupcount) == 1) {
+ release_slotlist(sl);
+ return -1;
+ }
+ /* this slot list (ours) will be skipped */
+ *cached_lookup = sl;
}
}
@@ -3500,11 +3593,13 @@
return error;
}
+
+
int dazuko_exit(void)
{
- int error;
+ int error;
int i;
- int j;
+
i = call_xp_atomic_read(&active);
@@ -3521,43 +3616,20 @@
call_xp_destroy_mutex(&mutex_unique_count);
call_xp_destroy_mutex(&mutex_amc);
- for (i=0 ; i<NUM_SLOT_LISTS ; i++)
+ for (i=0 ; i < NUM_SLOT_LISTS; i++)
{
- if (slot_lists[i].slot_list != NULL)
- {
-
dazuko_remove_all_paths(slot_lists[i].slot_list);
-
- if
(call_xp_atomic_read(&(slot_lists[i].slot_list->use_count)) != 0)
- call_xp_print("dazuko: slot_list count
was not 0 (possible bug)\n");
-
- for (j=0 ; j<NUM_SLOTS ; j++)
- {
-
call_xp_destroy_mutex(&(slot_lists[i].slot_list->slots[j].mutex));
-
call_xp_destroy_queue(&(slot_lists[i].slot_list->slots[j].wait_daemon_waiting_until_this_slot_not_READY));
-
call_xp_destroy_queue(&(slot_lists[i].slot_list->slots[j].wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
-
call_xp_destroy_queue(&(slot_lists[i].slot_list->slots[j].wait_daemon_waiting_until_this_slot_not_DONE));
- }
-
-
call_xp_destroy_rwlock(&(slot_lists[i].slot_list->lock_lists));
-
-
dazuko_remove_all_trusted(slot_lists[i].slot_list);
-
call_xp_destroy_rwlock(&(slot_lists[i].slot_list->lock_trusted_list));
-
-
call_xp_destroy_queue(&(slot_lists[i].slot_list->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
-
- if (slot_lists[i].slot_list->reg_name != NULL)
-
call_xp_free(slot_lists[i].slot_list->reg_name);
- slot_lists[i].slot_list->reg_name = NULL;
-
- call_xp_free(slot_lists[i].slot_list);
- slot_lists[i].slot_list = NULL;
- }
+ call_xp_down(&slot_lists[i].mutex);
+ if (slot_lists[i].slot_list)
+ release_slotlist(slot_lists[i].slot_list);
- call_xp_destroy_mutex(&(slot_lists[i].mutex));
+ call_xp_up(&slot_lists[i].mutex);
+ call_xp_destroy_mutex(&(slot_lists[i].mutex));
}
call_xp_print("dazuko: unloaded, version=%s\n", VERSION_STRING);
}
+ /* wait for all processes to release their slot list references..*/
+ msleep(200);
return error;
}
diff -ru origin/security/dazuko/dazuko_core.h new3/security/dazuko/dazuko_core.h
--- origin/security/dazuko/dazuko_core.h 2008-10-17 15:15:40.000000000
+0200
+++ new3/security/dazuko/dazuko_core.h 2008-10-22 14:59:07.000000000 +0200
@@ -201,7 +201,7 @@
int dazuko_vsnprintf(char *str, size_t size, const char *format, va_list ap);
int dazuko_snprintf(char *str, size_t size, const char *format, ...);
-int dazuko_is_our_daemon(struct xp_daemon_id *xp_id, struct slot_list
**slotlist, struct slot **slot);
+int dazuko_is_our_daemon(struct xp_daemon_id *xp_id, struct slot_list
**slotlist);
int dazuko_get_value(const char *key, const char *string, char **value);
int dazuko_unregister_daemon(struct xp_daemon_id *xp_id);
int dazuko_handle_user_request(const char *request_buffer, struct xp_daemon_id
*xp_id);
@@ -213,6 +213,7 @@
int dazuko_active(void);
int dazuko_check_access(unsigned long event, int daemon_is_allowed, struct
xp_daemon_id *xp_id, struct slot_list **cached_lookup);
int dazuko_process_access(unsigned long event, struct dazuko_file_struct *kfs,
struct event_properties *event_p, struct slot_list *cached_lookup);
+void dazuko_release_slotlist(struct slot_list *sl);
int dazuko_init(void);
int dazuko_exit(void);
diff -ru origin/security/dazuko/dazuko_linux26.c
new3/security/dazuko/dazuko_linux26.c
--- origin/security/dazuko/dazuko_linux26.c 2008-10-17 15:15:40.000000000
+0200
+++ new3/security/dazuko/dazuko_linux26.c 2008-10-22 14:59:07.000000000
+0200
@@ -636,6 +636,9 @@
dazuko_file_struct_cleanup(&dfs);
}
+ /* slot list may be null here */
+ if (sl)
+ dazuko_release_slotlist(sl);
}
if (error)
- [Dazuko-devel] Patch for patch-dazuko-linux-2.6.26,
Lino Sanfilippo <=