[Swan-dev] shunk_t vs chunk_t

D. Hugh Redelmeier hugh at mimosa.com
Mon Mar 1 19:38:23 UTC 2021


| From: Andrew Cagney <andrew.cagney at gmail.com>

| On Mon, 1 Mar 2021 at 10:17, D. Hugh Redelmeier <hugh at mimosa.com> wrote:
| >
| > In shunk_t
| >         const void *ptr;
| 
| BTW, it started out as const char * because it was being used on
| strings.  It changed to const void * as part of being made more
| generic.

const char * is not great.  const unsigned char * is better.  C
considers unsigned char to be the correct type for raw bytes.  char
can be signed and on some (rare!) machines 0xFF and 0x00 are equal chars.

| The nice thing about 'const void *' is that C compilers are ok with it
| being assigned to const pointers without a cast vis:
|    const uint8_t *p = shunk.ptr;
| vs the bug:
|    uint8_t *p = (uint8_t*)shunk.ptr;

It's true that const void * can be assigned to any (non-function)
pointer-to-const type.  But it cannot be indexed as if it were raw
bytes.

Do shunks or chunks ever hold anything other than raw bytes?  I count
ordinary C strings as raw bytes.

| > I understand why the former is const and the latter isn't.
| > But why do the base types differ?
| 
| History. chunk_t being (unsigned) bytes is pretty entrenched.

So I would have expected shunks to follow that.

| > I stubbed my toe on this yesterday.

in se_label_match:

	passert(a->ptr == NULL || (a->len > 0 && a->ptr[a->len - 1] == '\0'));

When "a" was a shunk_t *, it required an ugly cast:

	passert(a->ptr == NULL || (a->len > 0 && ((const uint8_t *)a->ptr)[a->len - 1] == '\0'));

| > ================
| >
| > Sometimes security labels are passed around in shunk_t and sometimes
| > chunk_t.  This is awkward and widespread.  I'm not sure if there is a good
| > cure because I haven't looked carefully.
| 
| > I chose to make the a and b parameters to se_label_match to have type
| > chunk_t * because that required the fewest casts.
| 
| Where?

Here are the four calls to se_label match.  Together there are eight
chunk_t * parameters, each for a security label.  In only one case is
the parameter cast to chunk_t *.

programs/pluto/connections.c:2480:			    && se_label_match(&sec_label, &sr->this.sec_label, logger)
programs/pluto/ikev1_spdb_struct.c:114:	if (!se_label_match((chunk_t *)&sec_label, &c->spd.this.sec_label, st->st_logger)) {
programs/pluto/ikev2_ts.c:887:			if (!se_label_match(&cur_i->sec_label, &d->spd.this.sec_label, logger)) {
programs/pluto/ikev2_ts.c:903:					} else if (se_label_match(&ends->r->sec_label, &d->spd.this.sec_label, logger)) {

| - the sec label provided by the acquire is NUL terminated byte stream
| (note, not string) (I hacked IKEv1 to enforce this, somewhere I've a
| patch for IKEv2)

Please do fix the IKEv2 case.  Right now there is code that
carelessly enforces the rule partially.  For example, in two places
in score_ends_seclabel().

| - since the sec_label bubbling up from the acquire points into a
| readonly-ish stack structure it's arguable that it should be a shunk_t

I would think so.

| where things break down is with IKEv2's struct traffic_selector (IKEv1
| very clearly clones the sec_label into struct state).
|
| My hunch is that IKEv2's struct traffic_selector should be a shunk_t.
| It starts out pointing into the pbs_in structure but then, when
| selected and saved, is cloned and stored in the same fields as for
| IKEv1 with lots of pointers updated.

Is the only magic in freeing the shunk?  Maybe we need a
free_shunk_content() where this magic is contained.


More information about the Swan-dev mailing list