Ship ubsan_minimal library in base?

2022-02-04 Thread Greg Steuck
How do people feel about shipping the minimal UBSan runtime library[1]
in the base system? It takes very little to build (Makefile + a few
ifdefs that both jca@ and I hacked together). The library is tiny and
useful enough for finding UB in base.

% ls -l /usr/lib/clang/13.0.0/lib/libclang_rt.ubsan_minimal*
-r--r--r--  1 root  bin  51516 Feb  4 20:02 
/usr/lib/clang/13.0.0/lib/libclang_rt.ubsan_minimal.a

% cd /usr/src/games/battlestar
% make obj && make clean; make LDFLAGS='-fsanitize=undefined 
-fsanitize-minimal-runtime' COPTS='-g -fsanitize=undefined 
-fsanitize-minimal-runtime -fno-wrapv'
% ./obj/battlestar
Version 4.2, fall 1984.
First Adventure game written by His Lordship, the honorable
Admiral D.W. Riggle

ubsan: shift-out-of-bounds

% egdb ./obj/battlestar 
(gdb) b __ubsan_handle_shift_out_of_bounds_minimal
Breakpoint 1 at 0x23630: file 
/usr/src/gnu/lib/libclang_rt/ubsan_minimal/../../../llvm/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp,
 line 104.
(gdb) bt
No stack.
(gdb) r
Starting program: /usr/obj/games/battlestar/battlestar 
Version 4.2, fall 1984.
First Adventure game written by His Lordship, the honorable
Admiral D.W. Riggle


Breakpoint 1, __ubsan_handle_shift_out_of_bounds_minimal ()
at 
/usr/src/gnu/lib/libclang_rt/ubsan_minimal/../../../llvm/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp:104
104 HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
(gdb) bt
#0  __ubsan_handle_shift_out_of_bounds_minimal ()
at 
/usr/src/gnu/lib/libclang_rt/ubsan_minimal/../../../llvm/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp:104
#1  0x07434ee9f654 in initialize (filename=) at 
/usr/src/games/battlestar/init.c:67
#2  0x07434ee8af06 in main (argc=1, argv=) at 
/usr/src/games/battlestar/battlestar.c:58

(gdb) up
#1  0x0b1eddd2a654 in initialize (filename=) at 
/usr/src/games/battlestar/init.c:67
67  SetBit(location[p->room].objects, p->obj);

(gdb) !grep SetBit extern.h
#define SetBit(array, index)(array[index/BITS] |= (1 << (index % BITS)))

Yup, the usual, shifting too far without 1U. Hence the patch:
--- a/games/battlestar/extern.h
+++ b/games/battlestar/extern.h
@@ -39,9 +39,9 @@
 #define OUTSIDE(position > 68 && position < 246 && position != 
218)
 #define rnd(x) arc4random_uniform(x)
 #define max(a,b)   ((a) < (b) ? (b) : (a))
-#define TestBit(array, index)  (array[index/BITS] & (1 << (index % BITS)))
-#define SetBit(array, index)   (array[index/BITS] |= (1 << (index % BITS)))
-#define ClearBit(array, index) (array[index/BITS] &= ~(1 << (index % BITS)))
+#define TestBit(array, index)  (array[index/BITS] & (1U << (index % BITS)))
+#define SetBit(array, index)   (array[index/BITS] |= (1U << (index % BITS)))
+#define ClearBit(array, index) (array[index/BITS] &= ~(1U << (index % BITS)))
 /*
  * These macros yield words to use with objects (followed but not preceded
  * by spaces, or with no spaces if the expansion is the empty string).

OK to fix battlestar while we are at it?

[1] https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#minimal-runtime



Re: convert bgpd to stdint.h types

2022-02-04 Thread David Gwynne
ok

On Sat, 5 Feb 2022, 01:08 Claudio Jeker,  wrote:

> This is something I wanted to do for a while. Switch from u_intXY_t to
> uintXY_t from stdint.h. The diff is mostly mechanical and was done with
> sed -i 's/u_intX_t/uintX_t/g' but uint8_t changes the tab spacing and so
> I had a look over the code and reindented where it made sense.
> Using stdint.h types will mostly help portability.
>
> Sorry for the size of this diff.
> --
> :wq Claudio
>
> Index: bgpctl/bgpctl.c
> ===
> RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
> retrieving revision 1.274
> diff -u -p -r1.274 bgpctl.c
> --- bgpctl/bgpctl.c 4 Feb 2022 12:01:33 -   1.274
> +++ bgpctl/bgpctl.c 4 Feb 2022 14:31:26 -
> @@ -54,9 +54,9 @@ void   show_mrt_dump(struct mrt_rib *, s
>  voidnetwork_mrt_dump(struct mrt_rib *, struct mrt_peer *,
> void *);
>  voidshow_mrt_state(struct mrt_bgp_state *, void *);
>  voidshow_mrt_msg(struct mrt_bgp_msg *, void *);
> -const char *msg_type(u_int8_t);
> +const char *msg_type(uint8_t);
>  voidnetwork_bulk(struct parse_result *);
> -int match_aspath(void *, u_int16_t, struct filter_as *);
> +int match_aspath(void *, uint16_t, struct filter_as *);
>
>  struct imsgbuf *ibuf;
>  struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state,
> show_mrt_msg };
> @@ -624,7 +624,7 @@ fmt_monotime(time_t t)
>  }
>
>  const char *
> -fmt_fib_flags(u_int16_t flags)
> +fmt_fib_flags(uint16_t flags)
>  {
> static char buf[8];
>
> @@ -665,7 +665,7 @@ fmt_fib_flags(u_int16_t flags)
>  }
>
>  const char *
> -fmt_origin(u_int8_t origin, int sum)
> +fmt_origin(uint8_t origin, int sum)
>  {
> switch (origin) {
> case ORIGIN_IGP:
> @@ -680,7 +680,7 @@ fmt_origin(u_int8_t origin, int sum)
>  }
>
>  const char *
> -fmt_flags(u_int8_t flags, int sum)
> +fmt_flags(uint8_t flags, int sum)
>  {
> static char buf[80];
> char flagstr[5];
> @@ -723,7 +723,7 @@ fmt_flags(u_int8_t flags, int sum)
>  }
>
>  const char *
> -fmt_ovs(u_int8_t validation_state, int sum)
> +fmt_ovs(uint8_t validation_state, int sum)
>  {
> switch (validation_state) {
> case ROA_INVALID:
> @@ -747,7 +747,7 @@ fmt_mem(long long num)
>  }
>
>  const char *
> -fmt_errstr(u_int8_t errcode, u_int8_t subcode)
> +fmt_errstr(uint8_t errcode, uint8_t subcode)
>  {
> static char  errbuf[256];
> const char  *errstr = NULL;
> @@ -814,7 +814,7 @@ fmt_errstr(u_int8_t errcode, u_int8_t su
>  }
>
>  const char *
> -fmt_attr(u_int8_t type, int flags)
> +fmt_attr(uint8_t type, int flags)
>  {
>  #define CHECK_FLAGS(s, t, m)   \
> if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1
> @@ -909,7 +909,7 @@ fmt_attr(u_int8_t type, int flags)
>  }
>
>  const char *
> -fmt_community(u_int16_t a, u_int16_t v)
> +fmt_community(uint16_t a, uint16_t v)
>  {
> static char buf[12];
>
> @@ -936,7 +936,7 @@ fmt_community(u_int16_t a, u_int16_t v)
>  }
>
>  const char *
> -fmt_large_community(u_int32_t d1, u_int32_t d2, u_int32_t d3)
> +fmt_large_community(uint32_t d1, uint32_t d2, uint32_t d3)
>  {
> static char buf[33];
>
> @@ -945,14 +945,14 @@ fmt_large_community(u_int32_t d1, u_int3
>  }
>
>  const char *
> -fmt_ext_community(u_int8_t *data)
> +fmt_ext_community(uint8_t *data)
>  {
> static char buf[32];
> -   u_int64_t   ext;
> +   uint64_text;
> struct in_addr  ip;
> -   u_int32_t   as4, u32;
> -   u_int16_t   as2, u16;
> -   u_int8_ttype, subtype;
> +   uint32_tas4, u32;
> +   uint16_tas2, u16;
> +   uint8_t type, subtype;
>
> type = data[0];
> subtype = data[1];
> @@ -1057,7 +1057,7 @@ network_bulk(struct parse_result *res)
> char *line = NULL;
> size_t linesize = 0;
> ssize_t linelen;
> -   u_int8_t len;
> +   uint8_t len;
> FILE *f;
>
> if ((f = fdopen(STDIN_FILENO, "r")) == NULL)
> @@ -1108,7 +1108,7 @@ show_mrt_dump_neighbors(struct mrt_rib *
>  {
> struct mrt_peer_entry *p;
> struct in_addr ina;
> -   u_int16_t i;
> +   uint16_t i;
>
> ina.s_addr = htonl(mp->bgp_id);
> printf("view: %s BGP ID: %s Number of peers: %u\n\n",
> @@ -1132,7 +1132,7 @@ show_mrt_dump(struct mrt_rib *mr, struct
> struct ctl_show_rib_request *req = arg;
> struct mrt_rib_entry*mre;
> time_t   now;
> -   u_int16_ti, j;
> +   uint16_t i, j;
>
> memset(&res, 0, sizeof(res));
> res.flags = req->flags;
> @@ -1214,7 +1214,7 @@ network_mrt_dump(struct mrt_rib *mr, str
> struct mrt_rib_entry*mre;
> struct ibuf *msg;
> time_t   now;

Re: convert bgpd to stdint.h types

2022-02-04 Thread Claudio Jeker
On Fri, Feb 04, 2022 at 07:20:21PM +0100, Theo Buehler wrote:
> On Fri, Feb 04, 2022 at 03:59:34PM +0100, Claudio Jeker wrote:
> > This is something I wanted to do for a while. Switch from u_intXY_t to
> > uintXY_t from stdint.h. The diff is mostly mechanical and was done with
> > sed -i 's/u_intX_t/uintX_t/g' but uint8_t changes the tab spacing and so
> > I had a look over the code and reindented where it made sense.
> > Using stdint.h types will mostly help portability.
> 
> ok (the only object change on amd64 is in util.c - not sure why).
> 
> I was wondering if u_char shouldn't be replaced as well.

There are u_char, u_short and u_int in bgpd. I have not fully made up my
mind about those. There will be a follow up diff for those.

-- 
:wq Claudio



Re: convert bgpd to stdint.h types

2022-02-04 Thread Theo Buehler
On Fri, Feb 04, 2022 at 03:59:34PM +0100, Claudio Jeker wrote:
> This is something I wanted to do for a while. Switch from u_intXY_t to
> uintXY_t from stdint.h. The diff is mostly mechanical and was done with
> sed -i 's/u_intX_t/uintX_t/g' but uint8_t changes the tab spacing and so
> I had a look over the code and reindented where it made sense.
> Using stdint.h types will mostly help portability.

ok (the only object change on amd64 is in util.c - not sure why).

I was wondering if u_char shouldn't be replaced as well.



Re: uvm_unmap_kill_entry(): unwire with map lock held

2022-02-04 Thread Martin Pieuchot
On 04/02/22(Fri) 03:39, Klemens Nanni wrote:
> [...] 
> ... with the lock grabbed in uvm_map_teardown() that is, otherwise
> the first call path can lock against itself (regress/misc/posixtestsuite
> is a reproduce for this):
> 
>   vm_map_lock_read_ln+0x38
>   uvm_fault_unwire+0x58
>   uvm_unmap_kill_entry_withlock+0x68
>   uvm_unmap_remove+0x2d4
>   sys_munmap+0x11c
> 
> which is obvious in hindsight.
> 
> So grabbing the lock in uvm_map_teardown() instead avoids that while
> still ensuring a locked map in the path missing a lock.

This should be fine since this function should only be called when the
last reference of a map is dropped.  In other words the locking here is
necessary to satisfy the assertions.

I wonder if lock shouldn't be taken & released around uvm_map_teardown()
which makes it easier to see that this is called after the last refcount
decrement. 

> Index: uvm_map.c
> ===
> RCS file: /cvs/src/sys/uvm/uvm_map.c,v
> retrieving revision 1.282
> diff -u -p -r1.282 uvm_map.c
> --- uvm_map.c 21 Dec 2021 22:21:32 -  1.282
> +++ uvm_map.c 4 Feb 2022 02:51:00 -
> @@ -2734,6 +2751,7 @@ uvm_map_teardown(struct vm_map *map)
>   KERNEL_ASSERT_UNLOCKED();
>  
>   KASSERT((map->flags & VM_MAP_INTRSAFE) == 0);
> + vm_map_lock(map);
>  
>   /* Remove address selectors. */
>   uvm_addr_destroy(map->uaddr_exe);
> 



Re: rpki-client: check certificate policies

2022-02-04 Thread Claudio Jeker
On Fri, Feb 04, 2022 at 03:56:18PM +0100, Theo Buehler wrote:
> On Fri, Feb 04, 2022 at 12:03:41PM +0100, Claudio Jeker wrote:
> > On Fri, Feb 04, 2022 at 10:41:03AM +0100, Theo Buehler wrote:
> > > It was pointed out to Claudio that rpki-client does not enforce
> > > certificate policies.
> > > 
> > > The diff below does that. It has two parts.
> > > 
> > > In cert.c we check that the certificate policy extension matches the
> > > specification in RFC 6487, section 4.8.9, as amended by RFC 7318
> > > section 2. That's maybe a bit lengthy but completely straightforward.
> > > If you're curious what's in a CPS URI, it might be this:
> > > https://www.arin.net/resources/manage/rpki/cps.pdf
> > > 
> > > The second bit is in parser.c and makes sure that the verifier builds a
> > > policy tree enforcing that the certification path uses a policy OID of
> > > id-cp-ipAddr-asNumber (see RFC 6484). This is a bit trickier since it
> > > involves X509_policy_check() under the hood. In short, we set up a
> > > policy containing that OID in the verify parameters and set verifier
> > > flags that ensure that the user set policy is enforced.
> > > 
> > > If you will, the second part improves the validation. The verifier
> > > doesn't have a mechanism to enforce things like there's exactly one
> > > policy identifier, etc. That's what's done in cert.c
> > > 
> > > This works for me. Please test.
> > 
> > Looks good to me. OK claudio@
> 
> Unfortunately, NID_ipAddr_asNumber is only available in LibreSSL 3.3 and
> later and didn't make it into OpenSSL 1.1 so I had to do some things a
> bit differently. I added a certpol_oid to x509_init_oid() and use it
> instead of NID_ipAddr_asNumber(). Since we have this global already,
> it's easier to use X509_VERIFY_PARAM_add0_policy(). It also forces one
> check to use OBJ_cmp() instead OBJ_obj2nid().

Sounds good to me. A comment below to that.
 
> > > + policy = sk_POLICYINFO_value(policies, 0);
> > > + assert(policy != NULL && policy->policyid != NULL);
> > 
> > Should this be an assert() or a proper error check?
> > I guess sk_POLICYINFO_value() can not really fail because of the check
> > above. What about policy->policyid? I gess X509V3_EXT_d2i() sets this
> > correctly or it failed above.
> 
> Yes. Both != NULL are guaranteed. You're right about sk_value(). Also
> your guess is correct: policy->policyid != NULL is guaranteed by the
> templated ASN.1:
> 
> In POLICYINFO_seq_tt (lib/libcrypto/x509/x509_cpols.c:147), there is no
> ASN1_TFLG_OPTIONAL flag to indicate that policy->policyid can be NULL
> (whereas policy->qualifiers is optional). Therefore if policy != NULL
> and since X509V3_EXT_d2i didn't fail, it must have deserialized
> correctly, so policy->policyid != NULL.
> 
> I left the assert as it is for now, but I can change it into an error
> check or drop it if you prefer.

I think the assert() is OK. I just want to make sure we don't abuse
assert() for proper error checking. There were some of those in the
codebase and in the end less assert() calls are preferred.
 
> > > + qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
> > > + assert(qualifier != NULL && qualifier->pqualid != NULL);
> > 
> > Same as above.
> 
> The answer is the same again, this time arguing with the flags in
> POLICYQUALINFO_seq_tt.
> 
> > > + flags |= X509_V_FLAG_EXPLICIT_POLICY;
> > > + flags |= X509_V_FLAG_INHIBIT_MAP;
> > 
> > I do not really understand the meaning of X509_V_FLAG_INHIBIT_MAP. Neither
> > the manpage nor the referenced RFC really help to explain what is
> > inhibited and if we really want that or not. It seems to be the more
> > strict option so I think it is the right thing to do but wow this is
> > complicated.
> 
> It is super complicated indeed. Policy mappings are explained here:
> https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.5
> It's another extension that allows translation between policy OIDs.
> I'm pretty sure we don't want to allow this.

Yes, I came to a similar conclusion after reading too much of rfc5280 for
my taste. Maybe something to reconsider once rfc8360 is needed (I still
hope it will just die and instead the original policy will be updated).
 
> Index: cert.c
> ===
> RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
> retrieving revision 1.53
> diff -u -p -r1.53 cert.c
> --- cert.c20 Jan 2022 16:36:19 -  1.53
> +++ cert.c4 Feb 2022 14:32:50 -
> @@ -29,6 +29,7 @@
>  
>  #include 
>  #include 
> +#include 
>  
>  #include "extern.h"
>  
> @@ -47,6 +48,7 @@ struct  parse {
>   const char  *fn; /* currently-parsed file */
>  };
>  
> +extern ASN1_OBJECT   *certpol_oid;   /* id-cp-ipAddr-asNumber cert policy */
>  extern ASN1_OBJECT   *carepo_oid;/* 1.3.6.1.5.5.7.48.5 (caRepository) */
>  extern ASN1_OBJECT   *manifest_oid;  /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
>  extern ASN1_OBJECT   *notify_oid;/* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
> @@ 

Re: rpki-client: check certificate policies

2022-02-04 Thread Theo Buehler
On Fri, Feb 04, 2022 at 12:03:41PM +0100, Claudio Jeker wrote:
> On Fri, Feb 04, 2022 at 10:41:03AM +0100, Theo Buehler wrote:
> > It was pointed out to Claudio that rpki-client does not enforce
> > certificate policies.
> > 
> > The diff below does that. It has two parts.
> > 
> > In cert.c we check that the certificate policy extension matches the
> > specification in RFC 6487, section 4.8.9, as amended by RFC 7318
> > section 2. That's maybe a bit lengthy but completely straightforward.
> > If you're curious what's in a CPS URI, it might be this:
> > https://www.arin.net/resources/manage/rpki/cps.pdf
> > 
> > The second bit is in parser.c and makes sure that the verifier builds a
> > policy tree enforcing that the certification path uses a policy OID of
> > id-cp-ipAddr-asNumber (see RFC 6484). This is a bit trickier since it
> > involves X509_policy_check() under the hood. In short, we set up a
> > policy containing that OID in the verify parameters and set verifier
> > flags that ensure that the user set policy is enforced.
> > 
> > If you will, the second part improves the validation. The verifier
> > doesn't have a mechanism to enforce things like there's exactly one
> > policy identifier, etc. That's what's done in cert.c
> > 
> > This works for me. Please test.
> 
> Looks good to me. OK claudio@

Unfortunately, NID_ipAddr_asNumber is only available in LibreSSL 3.3 and
later and didn't make it into OpenSSL 1.1 so I had to do some things a
bit differently. I added a certpol_oid to x509_init_oid() and use it
instead of NID_ipAddr_asNumber(). Since we have this global already,
it's easier to use X509_VERIFY_PARAM_add0_policy(). It also forces one
check to use OBJ_cmp() instead OBJ_obj2nid().

> > +   policy = sk_POLICYINFO_value(policies, 0);
> > +   assert(policy != NULL && policy->policyid != NULL);
> 
> Should this be an assert() or a proper error check?
> I guess sk_POLICYINFO_value() can not really fail because of the check
> above. What about policy->policyid? I gess X509V3_EXT_d2i() sets this
> correctly or it failed above.

Yes. Both != NULL are guaranteed. You're right about sk_value(). Also
your guess is correct: policy->policyid != NULL is guaranteed by the
templated ASN.1:

In POLICYINFO_seq_tt (lib/libcrypto/x509/x509_cpols.c:147), there is no
ASN1_TFLG_OPTIONAL flag to indicate that policy->policyid can be NULL
(whereas policy->qualifiers is optional). Therefore if policy != NULL
and since X509V3_EXT_d2i didn't fail, it must have deserialized
correctly, so policy->policyid != NULL.

I left the assert as it is for now, but I can change it into an error
check or drop it if you prefer.

> > +   qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
> > +   assert(qualifier != NULL && qualifier->pqualid != NULL);
> 
> Same as above.

The answer is the same again, this time arguing with the flags in
POLICYQUALINFO_seq_tt.

> > +   flags |= X509_V_FLAG_EXPLICIT_POLICY;
> > +   flags |= X509_V_FLAG_INHIBIT_MAP;
> 
> I do not really understand the meaning of X509_V_FLAG_INHIBIT_MAP. Neither
> the manpage nor the referenced RFC really help to explain what is
> inhibited and if we really want that or not. It seems to be the more
> strict option so I think it is the right thing to do but wow this is
> complicated.

It is super complicated indeed. Policy mappings are explained here:
https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.5
It's another extension that allows translation between policy OIDs.
I'm pretty sure we don't want to allow this.

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.53
diff -u -p -r1.53 cert.c
--- cert.c  20 Jan 2022 16:36:19 -  1.53
+++ cert.c  4 Feb 2022 14:32:50 -
@@ -29,6 +29,7 @@
 
 #include 
 #include 
+#include 
 
 #include "extern.h"
 
@@ -47,6 +48,7 @@ structparse {
const char  *fn; /* currently-parsed file */
 };
 
+extern ASN1_OBJECT *certpol_oid;   /* id-cp-ipAddr-asNumber cert policy */
 extern ASN1_OBJECT *carepo_oid;/* 1.3.6.1.5.5.7.48.5 (caRepository) */
 extern ASN1_OBJECT *manifest_oid;  /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
 extern ASN1_OBJECT *notify_oid;/* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
@@ -969,6 +971,78 @@ out:
return rc;
 }
 
+static int
+certificate_policies(struct parse *p, X509_EXTENSION *ext)
+{
+   STACK_OF(POLICYINFO)*policies = NULL;
+   POLICYINFO  *policy;
+   STACK_OF(POLICYQUALINFO)*qualifiers;
+   POLICYQUALINFO  *qualifier;
+   int  nid;
+   int  rc = 0;
+
+   if (!X509_EXTENSION_get_critical(ext)) {
+   cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
+   "extension not critical", p->fn);
+   goto out;
+   }
+
+   if ((policies = X509V3_EXT_d2i(ext)

Re: m_pullup alingment crash armv7 sparc64

2022-02-04 Thread Alexander Bluhm
On Fri, Feb 04, 2022 at 07:27:38PM +1000, David Gwynne wrote:
> On Thu, Feb 03, 2022 at 11:39:50PM +0100, Alexander Bluhm wrote:
> > On Thu, Feb 03, 2022 at 10:22:46PM +1000, David Gwynne wrote:
> > > bpf should know better than this. it has all the information it needs to
> > > align the payload properly, it just doesnt make enough of an effort. can
> > > you try the diff below?
> > 
> > Diff seems to work.  regress/sbin/slaacd passes.
> > I have started a full regress run on armv7 and sparc64.

Regress passed.

> tun(4) uses EMSGSIZE for this, but errno(2) says EMSGSIZE means
> "Message too long". EINVAL sounds good.
> 
> want me to do it now?

As you move the code around, you can easily adopt the error code
now.

OK bluhm@



Re: always align data in m_pullup on all archs

2022-02-04 Thread David Gwynne
On Fri, Feb 04, 2022 at 11:39:56AM +0100, Alexander Bluhm wrote:
> On Fri, Feb 04, 2022 at 07:32:52PM +1000, David Gwynne wrote:
> > as discussed in "m_pullup alingment crash armv7 sparc64", at worst it
> > doesnt hurt to have m_pullup maintain the data alignment of payloads,
> > and at best it will encourage aligned loads even if the arch allows
> > unaligned accesses. aligned loads are faster than unaligned.
> >
> > ok?
> 
> adj is unsigned int, so assigning a mtod(m0, unsigned long) looks
> strange.  Of course the higher bits are cut off anyway, but an
> explicit & is clearer than a assingment with different types.
> 
> Please use
> 
>   adj = mtod(m, unsigned long) & (sizeof(long) - 1);
>   adj = mtod(m0, unsigned long) & (sizeof(long) - 1);
> 
> otherwise OK bluhm@

it's been pointed out to me that ALIGNBYTES is actually very
conservative about alignment rather than optimistic. ie, it's at least
sizeof(long) - 1, but can be bigger. i think i've been confusing
it with ALIGNED_POINTER.

> 
> > Index: uipc_mbuf.c
> > ===
> > RCS file: /cvs/src/sys/kern/uipc_mbuf.c,v
> > retrieving revision 1.280
> > diff -u -p -r1.280 uipc_mbuf.c
> > --- uipc_mbuf.c 18 Jan 2022 12:38:21 -  1.280
> > +++ uipc_mbuf.c 4 Feb 2022 09:30:02 -
> > @@ -945,9 +945,11 @@ m_pullup(struct mbuf *m0, int len)
> > goto freem0;
> > }
> >
> > -   adj = mtod(m, unsigned long) & ALIGNBYTES;
> > +   adj = mtod(m, unsigned long);
> > } else
> > -   adj = mtod(m0, unsigned long) & ALIGNBYTES;
> > +   adj = mtod(m0, unsigned long);
> > +
> > +   adj &= sizeof(long) - 1;
> >
> > tail = head + M_SIZE(m0);
> > head += adj;



Re: openbgpd vs illumos

2022-02-04 Thread David Gwynne
Ok

On Fri, 4 Feb 2022, 21:19 Claudio Jeker,  wrote:

> On illumos sun is defined by some header so better not use sun as a
> variable name. Rename variable to sa_un to reduce hacks in -portable.
>
> --
> :wq Claudio
>
> Index: bgpctl/bgpctl.c
> ===
> RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
> retrieving revision 1.273
> diff -u -p -r1.273 bgpctl.c
> --- bgpctl/bgpctl.c 9 Aug 2021 08:24:36 -   1.273
> +++ bgpctl/bgpctl.c 4 Feb 2022 11:10:31 -
> @@ -78,7 +78,7 @@ usage(void)
>  int
>  main(int argc, char *argv[])
>  {
> -   struct sockaddr_un   sun;
> +   struct sockaddr_un   sa_un;
> int  fd, n, done, ch, verbose = 0;
> struct imsg  imsg;
> struct network_confignet;
> @@ -160,12 +160,12 @@ main(int argc, char *argv[])
> if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
> err(1, "control_init: socket");
>
> -   bzero(&sun, sizeof(sun));
> -   sun.sun_family = AF_UNIX;
> -   if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >=
> -   sizeof(sun.sun_path))
> +   bzero(&sa_un, sizeof(sa_un));
> +   sa_un.sun_family = AF_UNIX;
> +   if (strlcpy(sa_un.sun_path, sockname, sizeof(sa_un.sun_path)) >=
> +   sizeof(sa_un.sun_path))
> errx(1, "socket name too long");
> -   if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
> +   if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1)
> err(1, "connect: %s", sockname);
>
> if (pledge("stdio", NULL) == -1)
> Index: bgpd/control.c
> ===
> RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
> retrieving revision 1.105
> diff -u -p -r1.105 control.c
> --- bgpd/control.c  27 Apr 2021 15:34:18 -  1.105
> +++ bgpd/control.c  4 Feb 2022 11:07:25 -
> @@ -42,19 +42,19 @@ ssize_t  imsg_read_nofd(struct imsgbuf
>  int
>  control_check(char *path)
>  {
> -   struct sockaddr_un   sun;
> +   struct sockaddr_un   sa_un;
> int  fd;
>
> -   bzero(&sun, sizeof(sun));
> -   sun.sun_family = AF_UNIX;
> -   strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
> +   bzero(&sa_un, sizeof(sa_un));
> +   sa_un.sun_family = AF_UNIX;
> +   strlcpy(sa_un.sun_path, path, sizeof(sa_un.sun_path));
>
> if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) {
> log_warn("%s: socket", __func__);
> return (-1);
> }
>
> -   if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0) {
> +   if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == 0) {
> log_warnx("control socket %s already in use", path);
> close(fd);
> return (-1);
> @@ -68,7 +68,7 @@ control_check(char *path)
>  int
>  control_init(int restricted, char *path)
>  {
> -   struct sockaddr_un   sun;
> +   struct sockaddr_un   sa_un;
> int  fd;
> mode_t   old_umask, mode;
>
> @@ -78,10 +78,10 @@ control_init(int restricted, char *path)
> return (-1);
> }
>
> -   bzero(&sun, sizeof(sun));
> -   sun.sun_family = AF_UNIX;
> -   if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
> -   sizeof(sun.sun_path)) {
> +   bzero(&sa_un, sizeof(sa_un));
> +   sa_un.sun_family = AF_UNIX;
> +   if (strlcpy(sa_un.sun_path, path, sizeof(sa_un.sun_path)) >=
> +   sizeof(sa_un.sun_path)) {
> log_warn("control_init: socket name too long");
> close(fd);
> return (-1);
> @@ -102,7 +102,7 @@ control_init(int restricted, char *path)
> mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
> }
>
> -   if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
> +   if (bind(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1) {
> log_warn("control_init: bind: %s", path);
> close(fd);
> umask(old_umask);
> @@ -159,12 +159,12 @@ control_accept(int listenfd, int restric
>  {
> int  connfd;
> socklen_tlen;
> -   struct sockaddr_un   sun;
> +   struct sockaddr_un   sa_un;
> struct ctl_conn *ctl_conn;
>
> -   len = sizeof(sun);
> +   len = sizeof(sa_un);
> if ((connfd = accept4(listenfd,
> -   (struct sockaddr *)&sun, &len,
> +   (struct sockaddr *)&sa_un, &len,
> SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) {
> if (errno == ENFILE || errno == EMFILE) {
> pauseaccept = getmonotime();
>
>


Re: hardware checksum ix and ixl

2022-02-04 Thread David Gwynne
On Fri, Jan 28, 2022 at 05:26:01PM +0100, Alexander Bluhm wrote:
> On Wed, Jan 26, 2022 at 11:05:51AM +0100, Claudio Jeker wrote:
> > On Wed, Jan 26, 2022 at 01:29:42AM +0100, Alexander Bluhm wrote:
> > > Hi,
> > > 
> > > There were some problems with ix(4) and ixl(4) hardware checksumming
> > > for the output path on strict alignment architectures.
> > > 
> > > I have merged jan@'s diffs and added some sanity checks and
> > > workarounds.
> > > 
> > > - If the first mbuf is not aligned or not contigous, use m_copydata()
> > >   to extract the IP, IPv6, TCP header.
> > > - If the header is in the first mbuf, use m_data for the fast path.
> > > - Add netstat counter for invalid header chains.  This makes
> > >   us aware when hardware checksumming fails.
> > > - Add netstat counter for header copies.  This indicates that
> > >   better storage allocation in the network stack is possible.
> > >   It also allows to recognize alignment problems on non-strict
> > >   architectures.
> > > - There is not risk of crashes on sparc64.
> > > 
> > > Does this aproach make sense?
> > 
> > I think it is overly complicated and too much data is copied around.
> > First of all there is no need to extract ipproto.
> > The code can just use the M_TCP_CSUM_OUT and M_UDP_CSUM_OUT flags (they
> > are not set for other protos).
> > Because of this only they ip_hlen needs to be accessed and this can be
> > done with m_getptr().
> 
> A solution with m_getptr() is where we started.  It has already
> been rejected.  The problem is that there are 6 ways to implement
> this feature.  Every option has its drawbacks and was rejected.
> 
> Options are:
> 1. m_getptr() and access the struct.  Alignment cannot be guaranteed.
> 2. m_getptr() and access the byte or word.  Header fields should be
>accessed by structs.
> 3. Always m_copydata.  Too much overhead.
> 4. Always use m_data.  Kernel may crash or use invalid data.
> 5. Combination of m_data and m_copydata.  Too complex.
> 6. Track the fields in mbuf header.  Too fragile and memory overhead.
> 
> In my measurements checksum offloading gave us 10% performance boost
> so I want this feature.  Other drivers also have it.
> 
> Could we get another idea or find a consensus which option to use?

after staring at this for a few hours my conclusion is option 1 actually
is the right approach, but the diff for ixl has a bug.

> > In the IP6 case even more can be skipped since ip_hlen is static for IPv6.
> > 
> > In ixl(4) also the tcp header lenght needs to be extracted. Again the code
> > can be simplified because HW checksumming is only enabled if ip_hlen == 5
> > and so the offset of the th_off field is static (for both IPv4 and IPv6).
> > Again m_getptr can be used to just access the byte with th_off.
> > 
> > Longterm in_proto_cksum_out() should probably help provide the th_off
> > field. I think enforcing ip_hlen == 5 for UDP and TCP is fine, who needs
> > IP options on UDP and TCP?
> 
> Other diffs have been rejected as they make too many assumtions how
> the stack works.

my opinion is we can make these assumptions. the CSUM_OUT flags are
only set in very specific places where the stack itself is constructing
or checking properly aligned headers, and then the stack maintains
this alignment until it reaches the driver. this is where the first
of the bugs in the ixl diff comes in.

in the diff ixl_tx_setup_offload() is called after the dma mapping
occurs. this is implemented in this code:

static inline int
ixl_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m)
{
int error;

error = bus_dmamap_load_mbuf(dmat, map, m,
BUS_DMA_STREAMING | BUS_DMA_NOWAIT);
if (error != EFBIG)
return (error);

error = m_defrag(m, M_DONTWAIT);
if (error != 0)
return (error);

return (bus_dmamap_load_mbuf(dmat, map, m,
BUS_DMA_STREAMING | BUS_DMA_NOWAIT));
}

the problem is that when we get a heavily fragmented mbuf we call
m_defrag, which basically allocates a cluster and copies all the
data from the fragments into it. however, m_defrag does not maintain
the alignment of payload, meaning the ethernet header gets to start
on a 4 byte boundary cos that's what we get from the cluster pool,
and the IP and TCP payloads end up with a 2 byte misalignmnet.

my proposed solution to this is to set up the offload bits before
calling ixl_load_mbuf. i'm confident this is the bug that deraadt@ hit.

because of when the CSUM_OUT flags are set, i think m_getptr is fine for
pulling the mbuf apart. if it's not i want the code to blow up so it
gets fixed. that's why the code in my diff below lacks defenses.

the other bug is that the uint64_t holding the offload flags isn't
reset between being called for different mbufs. my solution to that is
to have ixl_tx_setup_offload() return the flags so the value in
ixl_start is overwritten every time.

lastly, ixl shouldn't (doesn't need to?) spelunk in the packet if
t

openbgpd vs illumos

2022-02-04 Thread Claudio Jeker
On illumos sun is defined by some header so better not use sun as a
variable name. Rename variable to sa_un to reduce hacks in -portable.

-- 
:wq Claudio

Index: bgpctl/bgpctl.c
===
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.273
diff -u -p -r1.273 bgpctl.c
--- bgpctl/bgpctl.c 9 Aug 2021 08:24:36 -   1.273
+++ bgpctl/bgpctl.c 4 Feb 2022 11:10:31 -
@@ -78,7 +78,7 @@ usage(void)
 int
 main(int argc, char *argv[])
 {
-   struct sockaddr_un   sun;
+   struct sockaddr_un   sa_un;
int  fd, n, done, ch, verbose = 0;
struct imsg  imsg;
struct network_confignet;
@@ -160,12 +160,12 @@ main(int argc, char *argv[])
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
err(1, "control_init: socket");
 
-   bzero(&sun, sizeof(sun));
-   sun.sun_family = AF_UNIX;
-   if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >=
-   sizeof(sun.sun_path))
+   bzero(&sa_un, sizeof(sa_un));
+   sa_un.sun_family = AF_UNIX;
+   if (strlcpy(sa_un.sun_path, sockname, sizeof(sa_un.sun_path)) >=
+   sizeof(sa_un.sun_path))
errx(1, "socket name too long");
-   if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+   if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1)
err(1, "connect: %s", sockname);
 
if (pledge("stdio", NULL) == -1)
Index: bgpd/control.c
===
RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
retrieving revision 1.105
diff -u -p -r1.105 control.c
--- bgpd/control.c  27 Apr 2021 15:34:18 -  1.105
+++ bgpd/control.c  4 Feb 2022 11:07:25 -
@@ -42,19 +42,19 @@ ssize_t  imsg_read_nofd(struct imsgbuf 
 int
 control_check(char *path)
 {
-   struct sockaddr_un   sun;
+   struct sockaddr_un   sa_un;
int  fd;
 
-   bzero(&sun, sizeof(sun));
-   sun.sun_family = AF_UNIX;
-   strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+   bzero(&sa_un, sizeof(sa_un));
+   sa_un.sun_family = AF_UNIX;
+   strlcpy(sa_un.sun_path, path, sizeof(sa_un.sun_path));
 
if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) {
log_warn("%s: socket", __func__);
return (-1);
}
 
-   if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0) {
+   if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == 0) {
log_warnx("control socket %s already in use", path);
close(fd);
return (-1);
@@ -68,7 +68,7 @@ control_check(char *path)
 int
 control_init(int restricted, char *path)
 {
-   struct sockaddr_un   sun;
+   struct sockaddr_un   sa_un;
int  fd;
mode_t   old_umask, mode;
 
@@ -78,10 +78,10 @@ control_init(int restricted, char *path)
return (-1);
}
 
-   bzero(&sun, sizeof(sun));
-   sun.sun_family = AF_UNIX;
-   if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
-   sizeof(sun.sun_path)) {
+   bzero(&sa_un, sizeof(sa_un));
+   sa_un.sun_family = AF_UNIX;
+   if (strlcpy(sa_un.sun_path, path, sizeof(sa_un.sun_path)) >=
+   sizeof(sa_un.sun_path)) {
log_warn("control_init: socket name too long");
close(fd);
return (-1);
@@ -102,7 +102,7 @@ control_init(int restricted, char *path)
mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
}
 
-   if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+   if (bind(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1) {
log_warn("control_init: bind: %s", path);
close(fd);
umask(old_umask);
@@ -159,12 +159,12 @@ control_accept(int listenfd, int restric
 {
int  connfd;
socklen_tlen;
-   struct sockaddr_un   sun;
+   struct sockaddr_un   sa_un;
struct ctl_conn *ctl_conn;
 
-   len = sizeof(sun);
+   len = sizeof(sa_un);
if ((connfd = accept4(listenfd,
-   (struct sockaddr *)&sun, &len,
+   (struct sockaddr *)&sa_un, &len,
SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) {
if (errno == ENFILE || errno == EMFILE) {
pauseaccept = getmonotime();



Re: rpki-client: check certificate policies

2022-02-04 Thread Claudio Jeker
On Fri, Feb 04, 2022 at 10:41:03AM +0100, Theo Buehler wrote:
> It was pointed out to Claudio that rpki-client does not enforce
> certificate policies.
> 
> The diff below does that. It has two parts.
> 
> In cert.c we check that the certificate policy extension matches the
> specification in RFC 6487, section 4.8.9, as amended by RFC 7318
> section 2. That's maybe a bit lengthy but completely straightforward.
> If you're curious what's in a CPS URI, it might be this:
> https://www.arin.net/resources/manage/rpki/cps.pdf
> 
> The second bit is in parser.c and makes sure that the verifier builds a
> policy tree enforcing that the certification path uses a policy OID of
> id-cp-ipAddr-asNumber (see RFC 6484). This is a bit trickier since it
> involves X509_policy_check() under the hood. In short, we set up a
> policy containing that OID in the verify parameters and set verifier
> flags that ensure that the user set policy is enforced.
> 
> If you will, the second part improves the validation. The verifier
> doesn't have a mechanism to enforce things like there's exactly one
> policy identifier, etc. That's what's done in cert.c
> 
> This works for me. Please test.

Looks good to me. OK claudio@
Few questions below.
 
> Index: cert.c
> ===
> RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
> retrieving revision 1.53
> diff -u -p -r1.53 cert.c
> --- cert.c20 Jan 2022 16:36:19 -  1.53
> +++ cert.c4 Feb 2022 09:09:38 -
> @@ -29,6 +29,7 @@
>  
>  #include 
>  #include 
> +#include 
>  
>  #include "extern.h"
>  
> @@ -969,6 +970,77 @@ out:
>   return rc;
>  }
>  
> +static int
> +certificate_policies(struct parse *p, X509_EXTENSION *ext)
> +{
> + STACK_OF(POLICYINFO)*policies = NULL;
> + POLICYINFO  *policy;
> + STACK_OF(POLICYQUALINFO)*qualifiers;
> + POLICYQUALINFO  *qualifier;
> + int  nid;
> + int  rc = 0;
> +
> + if (!X509_EXTENSION_get_critical(ext)) {
> + cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
> + "extension not critical", p->fn);
> + goto out;
> + }
> +
> + if ((policies = X509V3_EXT_d2i(ext)) == NULL) {
> + cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
> + "failed extension parse", p->fn);
> + goto out;
> + }
> +
> + if (sk_POLICYINFO_num(policies) != 1) {
> + warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
> + "want 1 policy, got %d", p->fn,
> + sk_POLICYINFO_num(policies));
> + goto out;
> + }
> +
> + policy = sk_POLICYINFO_value(policies, 0);
> + assert(policy != NULL && policy->policyid != NULL);

Should this be an assert() or a proper error check?
I guess sk_POLICYINFO_value() can not really fail because of the check
above. What about policy->policyid? I gess X509V3_EXT_d2i() sets this
correctly or it failed above.

> + if ((nid = OBJ_obj2nid(policy->policyid)) != NID_ipAddr_asNumber) {
> + warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
> + "unexpected policy identifier %d (%s)", p->fn, nid,
> + OBJ_nid2sn(nid));
> + goto out;
> + }
> +
> + /* Policy qualifiers are optional. If they're absent, we're done. */
> + if ((qualifiers = policy->qualifiers) == NULL) {
> + rc = 1;
> + goto out;
> + }
> +
> + if (sk_POLICYQUALINFO_num(qualifiers) != 1) {
> + warnx("%s: RFC 7318 section 2: certificatePolicies: "
> + "want 1 policy qualifier, got %d", p->fn,
> + sk_POLICYQUALINFO_num(qualifiers));
> + goto out;
> + }
> +
> + qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
> + assert(qualifier != NULL && qualifier->pqualid != NULL);

Same as above.

> + if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) {
> + warnx("%s: RFC 7318 section 2: certificatePolicies: "
> + "want CPS, got %d (%s)", p->fn, nid, OBJ_nid2sn(nid));
> + goto out;
> + }
> +
> + if (verbose > 1)
> + warnx("%s: CPS %.*s", p->fn, qualifier->d.cpsuri->length,
> + qualifier->d.cpsuri->data);
> +
> + rc = 1;
> + out:
> + sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
> + return rc;
> +}
> +
>  /*
>   * Parse and partially validate an RPKI X509 certificate (either a trust
>   * anchor or a certificate) as defined in RFC 6487.
> @@ -1024,6 +1096,9 @@ cert_parse_inner(const char *fn, const u
>   case NID_sinfo_access:
>   sia_present = 1;
>   c = sbgp_sia(&p, ext);
> + break;
> + case NID_certificate_policies:
> + c = certifi

Re: always align data in m_pullup on all archs

2022-02-04 Thread Alexander Bluhm
On Fri, Feb 04, 2022 at 07:32:52PM +1000, David Gwynne wrote:
> as discussed in "m_pullup alingment crash armv7 sparc64", at worst it
> doesnt hurt to have m_pullup maintain the data alignment of payloads,
> and at best it will encourage aligned loads even if the arch allows
> unaligned accesses. aligned loads are faster than unaligned.
> 
> ok?

adj is unsigned int, so assigning a mtod(m0, unsigned long) looks
strange.  Of course the higher bits are cut off anyway, but an
explicit & is clearer than a assingment with different types.

Please use

adj = mtod(m, unsigned long) & (sizeof(long) - 1);
adj = mtod(m0, unsigned long) & (sizeof(long) - 1);

otherwise OK bluhm@

> Index: uipc_mbuf.c
> ===
> RCS file: /cvs/src/sys/kern/uipc_mbuf.c,v
> retrieving revision 1.280
> diff -u -p -r1.280 uipc_mbuf.c
> --- uipc_mbuf.c   18 Jan 2022 12:38:21 -  1.280
> +++ uipc_mbuf.c   4 Feb 2022 09:30:02 -
> @@ -945,9 +945,11 @@ m_pullup(struct mbuf *m0, int len)
>   goto freem0;
>   }
>  
> - adj = mtod(m, unsigned long) & ALIGNBYTES;
> + adj = mtod(m, unsigned long);
>   } else
> - adj = mtod(m0, unsigned long) & ALIGNBYTES;
> + adj = mtod(m0, unsigned long);
> +
> + adj &= sizeof(long) - 1;
>  
>   tail = head + M_SIZE(m0);
>   head += adj;



rpki-client: check certificate policies

2022-02-04 Thread Theo Buehler
It was pointed out to Claudio that rpki-client does not enforce
certificate policies.

The diff below does that. It has two parts.

In cert.c we check that the certificate policy extension matches the
specification in RFC 6487, section 4.8.9, as amended by RFC 7318
section 2. That's maybe a bit lengthy but completely straightforward.
If you're curious what's in a CPS URI, it might be this:
https://www.arin.net/resources/manage/rpki/cps.pdf

The second bit is in parser.c and makes sure that the verifier builds a
policy tree enforcing that the certification path uses a policy OID of
id-cp-ipAddr-asNumber (see RFC 6484). This is a bit trickier since it
involves X509_policy_check() under the hood. In short, we set up a
policy containing that OID in the verify parameters and set verifier
flags that ensure that the user set policy is enforced.

If you will, the second part improves the validation. The verifier
doesn't have a mechanism to enforce things like there's exactly one
policy identifier, etc. That's what's done in cert.c

This works for me. Please test.

Index: cert.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.53
diff -u -p -r1.53 cert.c
--- cert.c  20 Jan 2022 16:36:19 -  1.53
+++ cert.c  4 Feb 2022 09:09:38 -
@@ -29,6 +29,7 @@
 
 #include 
 #include 
+#include 
 
 #include "extern.h"
 
@@ -969,6 +970,77 @@ out:
return rc;
 }
 
+static int
+certificate_policies(struct parse *p, X509_EXTENSION *ext)
+{
+   STACK_OF(POLICYINFO)*policies = NULL;
+   POLICYINFO  *policy;
+   STACK_OF(POLICYQUALINFO)*qualifiers;
+   POLICYQUALINFO  *qualifier;
+   int  nid;
+   int  rc = 0;
+
+   if (!X509_EXTENSION_get_critical(ext)) {
+   cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
+   "extension not critical", p->fn);
+   goto out;
+   }
+
+   if ((policies = X509V3_EXT_d2i(ext)) == NULL) {
+   cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
+   "failed extension parse", p->fn);
+   goto out;
+   }
+
+   if (sk_POLICYINFO_num(policies) != 1) {
+   warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
+   "want 1 policy, got %d", p->fn,
+   sk_POLICYINFO_num(policies));
+   goto out;
+   }
+
+   policy = sk_POLICYINFO_value(policies, 0);
+   assert(policy != NULL && policy->policyid != NULL);
+
+   if ((nid = OBJ_obj2nid(policy->policyid)) != NID_ipAddr_asNumber) {
+   warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
+   "unexpected policy identifier %d (%s)", p->fn, nid,
+   OBJ_nid2sn(nid));
+   goto out;
+   }
+
+   /* Policy qualifiers are optional. If they're absent, we're done. */
+   if ((qualifiers = policy->qualifiers) == NULL) {
+   rc = 1;
+   goto out;
+   }
+
+   if (sk_POLICYQUALINFO_num(qualifiers) != 1) {
+   warnx("%s: RFC 7318 section 2: certificatePolicies: "
+   "want 1 policy qualifier, got %d", p->fn,
+   sk_POLICYQUALINFO_num(qualifiers));
+   goto out;
+   }
+
+   qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
+   assert(qualifier != NULL && qualifier->pqualid != NULL);
+
+   if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) {
+   warnx("%s: RFC 7318 section 2: certificatePolicies: "
+   "want CPS, got %d (%s)", p->fn, nid, OBJ_nid2sn(nid));
+   goto out;
+   }
+
+   if (verbose > 1)
+   warnx("%s: CPS %.*s", p->fn, qualifier->d.cpsuri->length,
+   qualifier->d.cpsuri->data);
+
+   rc = 1;
+ out:
+   sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
+   return rc;
+}
+
 /*
  * Parse and partially validate an RPKI X509 certificate (either a trust
  * anchor or a certificate) as defined in RFC 6487.
@@ -1024,6 +1096,9 @@ cert_parse_inner(const char *fn, const u
case NID_sinfo_access:
sia_present = 1;
c = sbgp_sia(&p, ext);
+   break;
+   case NID_certificate_policies:
+   c = certificate_policies(&p, ext);
break;
case NID_crl_distribution_points:
/* ignored here, handled later */
Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.58
diff -u -p -r1.58 parser.c
--- parser.c28 Jan 2022 15:30:23 -  1.58
+++ parser.c4 Feb 2022 00:15:02 -
@@ -43,9 +43,10 @@ stati

always align data in m_pullup on all archs

2022-02-04 Thread David Gwynne
as discussed in "m_pullup alingment crash armv7 sparc64", at worst it
doesnt hurt to have m_pullup maintain the data alignment of payloads,
and at best it will encourage aligned loads even if the arch allows
unaligned accesses. aligned loads are faster than unaligned.

ok?

Index: uipc_mbuf.c
===
RCS file: /cvs/src/sys/kern/uipc_mbuf.c,v
retrieving revision 1.280
diff -u -p -r1.280 uipc_mbuf.c
--- uipc_mbuf.c 18 Jan 2022 12:38:21 -  1.280
+++ uipc_mbuf.c 4 Feb 2022 09:30:02 -
@@ -945,9 +945,11 @@ m_pullup(struct mbuf *m0, int len)
goto freem0;
}
 
-   adj = mtod(m, unsigned long) & ALIGNBYTES;
+   adj = mtod(m, unsigned long);
} else
-   adj = mtod(m0, unsigned long) & ALIGNBYTES;
+   adj = mtod(m0, unsigned long);
+
+   adj &= sizeof(long) - 1;
 
tail = head + M_SIZE(m0);
head += adj;



Re: m_pullup alingment crash armv7 sparc64

2022-02-04 Thread David Gwynne
On Thu, Feb 03, 2022 at 11:39:50PM +0100, Alexander Bluhm wrote:
> On Thu, Feb 03, 2022 at 10:22:46PM +1000, David Gwynne wrote:
> > bpf should know better than this. it has all the information it needs to
> > align the payload properly, it just doesnt make enough of an effort. can
> > you try the diff below?
> 
> Diff seems to work.  regress/sbin/slaacd passes.
> I have started a full regress run on armv7 and sparc64.

cool.

> 
> > +   if (len < hlen)
> > +   return (EPERM);
> 
> This is not a permission problem.  Maybe EINVAL.

this is preveserving the existing semantics of this chunk:

@@ -232,10 +247,6 @@ bpf_movein(struct uio *uio, struct bpf_d
goto bad;
}
 
-   if (m->m_len < hlen) {
-   error = EPERM;
-   goto bad;
-   }
/*
 * Make room for link header, and copy it to sockaddr
 */

i was going to follow this diff up with another one to tweak it.
tun(4) uses EMSGSIZE for this, but errno(2) says EMSGSIZE means
"Message too long". EINVAL sounds good.

want me to do it now?

> 
> > +   /*
> > + * Get the length of the payload so we can align it properly.
> > +*/
> 
> Whitespace misaligned.

yep.

> > +   if (mlen > MAXMCLBYTES)
> > +   return (EIO);
> 
> Should we use EMSGSIZE like in bpfwrite() if the data does not fit.

yes. want me to do that now too?

> 
> > +   mlen = max(max_linkhdr, hlen) + roundup(alen, sizeof(long));
> ...
> > +   m_align(m, alen); /* Align the payload. */
> 
> sizeof(long) seems the correct alignment for mbuf.  In rev 1.237
> of m_pullup() you introduced ALIGNBYTES.  This is architecture
> dependent and the only place in the network stack where it is used.
> Should it also be sizeof(long) there?

i probably did that when i was adding ALIGNED_POINTER checks to ethernet
tunnel drivers.

my initial thought is it doesnt save m_pullup any work, so it's
probably better to use sizeof(long) so there's a better chance that
accesses to words in a pulled up payload are aligned. even if an
arch doesnt fault on unaligned access it still goes faster with
aligned accesses. if m_pullup is going to move data around it may as
well move it to the best place possible.

i'll spit a diff out for that next.

Index: bpf.c
===
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.210
diff -u -p -r1.210 bpf.c
--- bpf.c   16 Jan 2022 06:27:14 -  1.210
+++ bpf.c   4 Feb 2022 09:25:40 -
@@ -144,7 +144,7 @@ bpf_movein(struct uio *uio, struct bpf_d
struct mbuf *m;
struct m_tag *mtag;
int error;
-   u_int hlen;
+   u_int hlen, alen, mlen;
u_int len;
u_int linktype;
u_int slen;
@@ -198,23 +198,38 @@ bpf_movein(struct uio *uio, struct bpf_d
return (EIO);
}
 
-   if (uio->uio_resid > MAXMCLBYTES)
-   return (EIO);
len = uio->uio_resid;
+   if (len < hlen)
+   return (EPERM);
 
-   MGETHDR(m, M_WAIT, MT_DATA);
-   m->m_pkthdr.ph_ifidx = 0;
-   m->m_pkthdr.len = len - hlen;
+   /*
+* Get the length of the payload so we can align it properly.
+*/
+   alen = len - hlen;
+
+   /*
+* Allocate enough space for headers and the aligned payload.
+*/
+   mlen = max(max_linkhdr, hlen) + roundup(alen, sizeof(long));
+
+   if (mlen > MAXMCLBYTES)
+   return (EIO);
 
-   if (len > MHLEN) {
-   MCLGETL(m, M_WAIT, len);
+   MGETHDR(m, M_WAIT, MT_DATA);
+   if (mlen > MHLEN) {
+   MCLGETL(m, M_WAIT, mlen);
if ((m->m_flags & M_EXT) == 0) {
error = ENOBUFS;
goto bad;
}
}
+
+   m_align(m, alen); /* Align the payload. */
+   m->m_data -= hlen;
+
+   m->m_pkthdr.ph_ifidx = 0;
+   m->m_pkthdr.len = len;
m->m_len = len;
-   *mp = m;
 
error = uiomove(mtod(m, caddr_t), len, uio);
if (error)
@@ -232,10 +247,6 @@ bpf_movein(struct uio *uio, struct bpf_d
goto bad;
}
 
-   if (m->m_len < hlen) {
-   error = EPERM;
-   goto bad;
-   }
/*
 * Make room for link header, and copy it to sockaddr
 */
@@ -249,8 +260,10 @@ bpf_movein(struct uio *uio, struct bpf_d
sockp->sa_family = ntohl(af);
} else
memcpy(sockp->sa_data, m->m_data, hlen);
+
+   m->m_pkthdr.len -= hlen;
m->m_len -= hlen;
-   m->m_data += hlen; /* XXX */
+   m->m_data += hlen;
}
 
/*
@@ -260,6 +273,7 @@ bpf_movein(struct uio *uio, struct bpf_d
*(u_int *)(mtag + 1) = linktype;
m_tag_prepend(m, mtag);
 
+   *mp = m;
return (0);
  bad:
m_freem(m);