[Swan-dev] cur_state and friends [was Re:Fwd: Changes to ref refs/heads/master]
Andrew Cagney
andrew.cagney at gmail.com
Fri Jan 19 16:52:55 UTC 2018
On 16 January 2018 at 13:54, D. Hugh Redelmeier <hugh at mimosa.com> wrote:
> [All this is from fallible memory since archaeology is
> labour-intensive.]
>
> | From: Andrew Cagney <andrew.cagney at gmail.com>
>
> | Yea, this is part of a more general problem. But first some
> | background. We've always kind of sort of always had the stack:
> |
> | - cur_state | ... | cur_state | cur_connection | cur_from
>
> The original design apparently wasn't robust in the face of 20 years
> of maintenance. Either a little two intricate or not documented well
> enough.
Likely neither. No matter how good our, code has this annoying habit
of evolving in ways we don't expect but do work.
Here, it has ended up being used as a stack. It also isn't that
surprising as the code has a natural flow:
ip_address old_from = push_cur_from(md->sender);
process_packet(&md);
pop_cur_from(old_from);
or:
so_serial_t old_state = push_cur_state(st);
struct msg_digest *md = unsuspend_md(st);
(*cn->pcrc_func)(st, md, &cn->pcrc_pcr);
pop_cur_state(old_state);
or:
so_serial_t old_state = push_cur_state(st);
libreswan_log("XAUTH: #%lu: completed for user '%s' with status %s",
xauth->serialno, xauth->ptarg.name,
success ? "SUCCESSS" : "FAILURE");
xauth->callback(st, xauth->ptarg.name, success);
pop_cur_state(old_state);
or more generally:
st = find state
if st != NULL {
push st
process st
pop
}
and in IKEv2's auth code:
push parent
...
/* parent authenticated, start on child *.
push cst
finish child
pop cst
pop parent
(but the last one doesn't look like that, and I'd argue that is one of
the causes of a horrible PPK bug I hacked around)
> There really was no stack. But there was a priority. If cur_state was
> set, that was used to prefix logging. Otherwise, if cur_connection was
> set, that was used to prefix logging. cur_* were ONLY supposed to be used
> for logging.
>
> set_cur* were meant to be idempotent. Certainly not a feature of stack
> pushing. Idempotence makes correctness easier (eg. the change to
> timer_event_cb would not be required).
... or timer_event_cb() could be structured so that it better follows
the above flow
> Some (not many) routines needed to temporarily switch cur_state. It was
> their job to save the old cur_state value and later restore it. If this
> were common, a stack would make sense. With the transaction-processing
> design of Pluto, this was not at all common.
>
> There is a particular hazard with a routine privately saving a copy
> of cur_state. If that old state were deleted, who would prevent that
> dangling pointer being re-installed as cur_state? I don't think that
> case could come up, but who knows with all the code changes that have
> happened.
I fixed the case with cur_from. Since it has a copy of the address it
doesn't matter when MD gets deleted.
> One of my biggest sins was to use cur_state to smuggle the current state
> around some of the crypto code. It was meant to be a temporary hack until
> I got the next chunk of changes done and committed. But that didn't
> happen. I think Andrew fixed that recently with some refactoring.
>
> | - when a state gets deleted, there's general confusion over who should
> | be pushing/popping cur_state
>
> In the original design, only one thing ever deleted a state:
> delete_state().
>
> If cur_state pointed to the state to be deleted, delete_state would
> set it to NULL. But it didn't do that immediately since some of its
> diagnostics were usefully prefixed.
>
> Same pattern for cur_connection.
While my cur_from code works, I think there's an even simpler solution.
Instead of saving the current from / connection / state, simply
pre-format the prefix and and save that (possibly on a local stack)
(see LSWLOG_STRING()).
This way it doesn't matter if/when state or connection are deleted as
the prefix string is always valid. Code like this:
/* without st_connection, st isn't complete */
/* from here on logging is for the wrong state */
pop_cur_state(old_serialno);
isn't needed.
> With a stack, things get trickier. It's nice for things that act like
> brackets dynamically (i.e. in execution) to appear as brackets
> statically (i.e. in the code). That's not often the case with
> push_cur_state and pop_cur_state.
the above examples were mostly lifted from the code
More information about the Swan-dev
mailing list