agent: Fix detection of exit of scdaemon.

* agent/call-scd.c (start_scd): Acquire START_SCD_LOCK for
SCD_LOCAL_LIST.  Move common case code to fast path.
Release START_SCD_LOCK before calling unlock_scd.
When new CTX is allocated, clear INVALID flag.
(agent_reset_scd): Serialize the access to SCD_LOCAL_LIST by
START_SCD_LOCK.

--

GnuPG-bug-id: 4377
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2019-03-06 10:33:54 +09:00
parent 8d4af54ddd
commit 2abad7585a
1 changed files with 80 additions and 62 deletions

View File

@ -303,33 +303,19 @@ start_scd (ctrl_t ctrl)
if (opt.disable_scdaemon)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
/* If this is the first call for this session, setup the local data
structure. */
if (!ctrl->scd_local)
if (ctrl->scd_local && ctrl->scd_local->ctx)
{
ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local);
if (!ctrl->scd_local)
return gpg_error_from_syserror ();
ctrl->scd_local->next_local = scd_local_list;
scd_local_list = ctrl->scd_local;
ctrl->scd_local->in_use = 1;
return 0; /* Okay, the context is fine. */
}
if (ctrl->scd_local->in_use)
if (ctrl->scd_local && ctrl->scd_local->in_use)
{
log_error ("start_scd: CTX is in use\n");
return gpg_error (GPG_ERR_INTERNAL);
}
ctrl->scd_local->in_use = 1;
if (ctrl->scd_local->ctx)
return 0; /* Okay, the context is fine. We used to test for an
alive context here and do an disconnect. Now that we
have a ticker function to check for it, it is easier
not to check here but to let the connection run on an
error instead. */
/* We need to protect the following code. */
/* We need to serialize the access to scd_local_list and primary_scd_ctx. */
rc = npth_mutex_lock (&start_scd_lock);
if (rc)
{
@ -338,6 +324,25 @@ start_scd (ctrl_t ctrl)
return gpg_error (GPG_ERR_INTERNAL);
}
/* If this is the first call for this session, setup the local data
structure. */
if (!ctrl->scd_local)
{
ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local);
if (!ctrl->scd_local)
{
err = gpg_error_from_syserror ();
rc = npth_mutex_unlock (&start_scd_lock);
if (rc)
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
return err;
}
ctrl->scd_local->next_local = scd_local_list;
scd_local_list = ctrl->scd_local;
}
ctrl->scd_local->in_use = 1;
/* Check whether the pipe server has already been started and in
this case either reuse a lingering pipe connection or establish a
new socket based one. */
@ -522,6 +527,10 @@ start_scd (ctrl_t ctrl)
}
leave:
rc = npth_mutex_unlock (&start_scd_lock);
if (rc)
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
xfree (abs_homedir);
if (err)
{
@ -531,11 +540,9 @@ start_scd (ctrl_t ctrl)
}
else
{
ctrl->scd_local->invalid = 0;
ctrl->scd_local->ctx = ctx;
}
rc = npth_mutex_unlock (&start_scd_lock);
if (rc)
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
return err;
}
@ -554,15 +561,21 @@ agent_scd_check_running (void)
a cleanup of resources used by the current connection. */
int
agent_reset_scd (ctrl_t ctrl)
{
int err = npth_mutex_lock (&start_scd_lock);
if (err)
{
log_error ("failed to acquire the start_scd lock: %s\n",
strerror (err));
}
else
{
if (ctrl->scd_local)
{
if (ctrl->scd_local->ctx)
{
/* We can't disconnect the primary context because libassuan
does a waitpid on it and thus the system would hang.
Instead we send a reset and keep that connection for
reuse. */
/* We send a reset and keep that connection for reuse. */
if (ctrl->scd_local->ctx == primary_scd_ctx)
{
/* Send a RESTART to the SCD. This is required for the
@ -604,6 +617,11 @@ agent_reset_scd (ctrl_t ctrl)
ctrl->scd_local = NULL;
}
err = npth_mutex_unlock (&start_scd_lock);
if (err)
log_error ("failed to release the start_scd lock: %s\n", strerror (err));
}
return 0;
}