|
Description
|
bustos 2008-07-21
svc.configd's rc_node_delete() looks up the parent of the target node and
places a hold on it:
pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
if (pp == NULL) {
...
}
rc_node_hold_locked(pp); /* hold for later */
The function does release this hold with rc_node_rele_locked() on the error
paths, but not on the success path. This causes the rn_refs field never to be
decremented to 0, and the node never to be free()d.
Producing such a node should be a simple matter of creating a service, creating
a child of it (either an instance or a property group), and then deleting them
in reverse order.
The service node should hang around (in particular, it's rn_name and rn_fmri
should be in tact) with RC_NODE_DEAD (0x8000) set in its flags
and its rn_refs field set to 1 (rn_refs should be 0 when no clients are
connected). The node might not show up in ::findleaks right away, though, if
it's still referenced by the request_log[]. ::ugrep, ::whatis, and
request_log/X should indicate this, and it should be possible to flush the
reference in the log with a sufficient number of requests.
The fix should be to change the (void) pthread_mutex_unlock(&pp->rn_lock) in the
final if (pp != NULL) clause to rc_node_rele_locked(pp).
|