Re: route(4) manual and sockaddrs; ROUNDUP()

2019-07-15 Thread Vadim Penzin




On 7/15/19 12:45 PM, Claudio Jeker wrote:

On Mon, Jul 15, 2019 at 11:08:53AM +0300, Vadim Penzin wrote:



On 7/15/19 10:28 AM, Claudio Jeker wrote:

On Sun, Jul 14, 2019 at 01:15:40PM +0300, Vadim Penzin wrote:

Since `sa_len' describes the size of a `sockaddr' (or one of its
derivatives) /including/ `sa_len' (maybe I am wrong, but this is my
interpretation of the comment `total length' that appears near the
definition of `struct sockaddr' in ), `sa_len' just
cannot be zero.


Yes, it can not be zero.

The current definition of ROUNDUP() might hide a bug.  In addition, on
some machines, it disturbs the pipeline of the CPU by introducing a
branch (for no real reason, as it seems, while I might be
nitpicking). At very least, it looks confusing.


The following patch amends the issue:

Index: route.c
===
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.387
diff -u -p -r1.387 route.c
--- route.c 24 Jun 2019 22:26:25 -  1.387
+++ route.c 14 Jul 2019 10:05:04 -
@@ -138,7 +138,7 @@
   #include 
   #endif

-#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) :
sizeof(long))
+#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))

   /* Give some jitter to hash, to avoid synchronization between routers. */
   static uint32_trt_hashjitter;



This only touches only one version of ROUNDUP() and looking at how ROUNDUP()
is used in route.c I wonder if it is actually needed at all.
Looking at the code in route.c and rtsock.c I think it is better to leave
this like it is or fix both files making sure that the necessary checks
are put in place to make sure that a sa_len of 0 can't get into the system.



If you wish to remove ROUNDUP() then fine, however, leaving it as is does
not help.

Imagine the behaviour of the original ROUNDUP() in the unlikely event when
the kernel does somehow produce a sockaddr with sa_len of zero. The kernel
will send an unvalid sockaddr to the user. ROUNDUP() alone will not help
detection or correction of that fault.

Now imagine the behaviour of the new version. The kernel will not send an
incorrect sockaddr to the user (ROUNDUP() returns zero) but a sockaddr will
be missing entirely.

What is better: having something unusable and misleading or not having it
(with a good way of knowing that it is missing)?  That's philosophy to me.

In any case, ROUNDUP() cannot magically help when sa_len is zero.


Some time ago there was an infinite loop because of a 0 length advance and
so the parser code never moved over the data. At least this does not
happen with a ROUNDUP() that ensures that at least sizeof(long) data is
consumed on every call.

Keep in mind userland can send in any kind of crap and syzkaller told me
that the rtsock code is way to trusting. This is why I think this is
incomplete. The ROUNDUP() version in rtsock.c and route.c should be kept
in sync (and maybe moved to a .h file).



Unless I am missing something, ROUTE() is not used directly for parsing 
user data. ADVANCE() does `call' ROUTE() for parsing, and it would look 
more natural if ADVANCE() were checking that it, well, advances :-)


I think that explicit consistency checks and aborting calls early is a 
better strategy than relying on ROUNDUP()'s sweeping the garbage under 
the rug.


At any rate, providing a user-visible macro that reports the size of 
memory that is allocated for a sockaddr is a much-needed companion to 
route(4).  Digging knowledge up from the kernel sources should not be a 
strict condition for application development.




Re: route(4) manual and sockaddrs; ROUNDUP()

2019-07-15 Thread Vadim Penzin




On 7/15/19 10:28 AM, Claudio Jeker wrote:

On Sun, Jul 14, 2019 at 01:15:40PM +0300, Vadim Penzin wrote:

Since `sa_len' describes the size of a `sockaddr' (or one of its
derivatives) /including/ `sa_len' (maybe I am wrong, but this is my
interpretation of the comment `total length' that appears near the
definition of `struct sockaddr' in ), `sa_len' just
cannot be zero.


Yes, it can not be zero.

The current definition of ROUNDUP() might hide a bug.  In addition, on
some machines, it disturbs the pipeline of the CPU by introducing a
branch (for no real reason, as it seems, while I might be
nitpicking). At very least, it looks confusing.


The following patch amends the issue:

Index: route.c
===
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.387
diff -u -p -r1.387 route.c
--- route.c 24 Jun 2019 22:26:25 -  1.387
+++ route.c 14 Jul 2019 10:05:04 -
@@ -138,7 +138,7 @@
  #include 
  #endif

-#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) :
sizeof(long))
+#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))

  /* Give some jitter to hash, to avoid synchronization between routers. */
  static uint32_trt_hashjitter;



This only touches only one version of ROUNDUP() and looking at how ROUNDUP()
is used in route.c I wonder if it is actually needed at all.
Looking at the code in route.c and rtsock.c I think it is better to leave
this like it is or fix both files making sure that the necessary checks
are put in place to make sure that a sa_len of 0 can't get into the system.



If you wish to remove ROUNDUP() then fine, however, leaving it as is 
does not help.


Imagine the behaviour of the original ROUNDUP() in the unlikely event 
when the kernel does somehow produce a sockaddr with sa_len of zero. 
The kernel will send an unvalid sockaddr to the user. ROUNDUP() alone 
will not help detection or correction of that fault.


Now imagine the behaviour of the new version. The kernel will not send 
an incorrect sockaddr to the user (ROUNDUP() returns zero) but a 
sockaddr will be missing entirely.


What is better: having something unusable and misleading or not having 
it (with a good way of knowing that it is missing)?  That's philosophy 
to me.


In any case, ROUNDUP() cannot magically help when sa_len is zero.



Re: ifstated(8): Fix Hard-Coded Message Size

2019-07-15 Thread Vadim Penzin




On 7/15/19 10:15 AM, Claudio Jeker wrote:

On Sun, Jul 14, 2019 at 05:28:17PM +0300, Vadim Penzin wrote:

The following patch replaces the hard-coded message size of 2048 bytes in
ifstated.c:rt_msg_handler() with RTM_MAXSIZE (which is currently defined as
2048 bytes) that, I believe, was the intent of the author.

Index: ifstated.c
===
RCS file: /cvs/src/usr.sbin/ifstated/ifstated.c,v
retrieving revision 1.64
diff -u -p -r1.64 ifstated.c
--- ifstated.c  28 Jun 2019 13:32:47 -  1.64
+++ ifstated.c  14 Jul 2019 14:22:32 -
@@ -236,7 +236,7 @@ load_config(void)
  void
  rt_msg_handler(int fd, short event, void *arg)
  {
-   char msg[2048];
+   char msg[RTM_MAXSIZE];
struct rt_msghdr *rtm = (struct rt_msghdr *)
struct if_msghdr ifm;
struct if_announcemsghdr ifan;



I don't think RTM_MAXSIZE should be used outside of the kernel.
Especially for reading messages. I would leave the code as is.


In that case, please hide RTM_MAXSIZE using _KERNEL.  The definition of 
RTM_MAXSIZE is right above RTM_ADD which is user-visible according to 
the current documentation.


What about other defines?  Can user-space programs use RTM_VERSION, for 
instance?




portmap(8): Remove an odd call to endpwent(3)

2019-07-14 Thread Vadim Penzin
portmap(8) does not use setpassent(3) which is the only way of causing a 
successful call to getpwnam(3) not to close the password database, 
therefore the call to endpwent(3) seems to be unnecessary.


The following patch removes the call to endpwent(3):

Index: portmap.c
===
RCS file: /cvs/src/usr.sbin/portmap/portmap.c,v
retrieving revision 1.50
diff -u -p -r1.50 portmap.c
--- portmap.c   28 Jun 2019 13:32:49 -  1.50
+++ portmap.c   14 Jul 2019 15:29:27 -
@@ -245,7 +245,6 @@ main(int argc, char *argv[])
exit(1);
}
}
-   endpwent();

if (pledge("stdio inet proc", NULL) == -1)
err(1, "pledge");



ifstated(8): Fix Hard-Coded Message Size

2019-07-14 Thread Vadim Penzin
The following patch replaces the hard-coded message size of 2048 bytes 
in ifstated.c:rt_msg_handler() with RTM_MAXSIZE (which is currently 
defined as 2048 bytes) that, I believe, was the intent of the author.


Index: ifstated.c
===
RCS file: /cvs/src/usr.sbin/ifstated/ifstated.c,v
retrieving revision 1.64
diff -u -p -r1.64 ifstated.c
--- ifstated.c  28 Jun 2019 13:32:47 -  1.64
+++ ifstated.c  14 Jul 2019 14:22:32 -
@@ -236,7 +236,7 @@ load_config(void)
 void
 rt_msg_handler(int fd, short event, void *arg)
 {
-   char msg[2048];
+   char msg[RTM_MAXSIZE];
struct rt_msghdr *rtm = (struct rt_msghdr *)
struct if_msghdr ifm;
struct if_announcemsghdr ifan;



route(4): Manpage Clarifications + An Example

2019-07-14 Thread Vadim Penzin

Please find below a patch that contains the following:

(a) An explanation of alignment of address structures within a routing 
message;


(b) An example (I admit, it is somewhat lengthy --- 146 lines) of a 
basic parser of route(4) messages.


(This message is a follow-up to 
https://marc.info/?l=openbsd-tech=155627978527725)


Index: route.4
===
RCS file: /cvs/src/share/man/man4/route.4,v
retrieving revision 1.52
diff -u -p -r1.52 route.4
--- route.4 30 Apr 2019 16:34:19 -  1.52
+++ route.4 14 Jul 2019 13:39:33 -
@@ -137,13 +137,13 @@ routing information for all address fami
 to a specific address family by specifying which one is desired.
 There can be more than one routing socket open per system.
 .Pp
-Messages are formed by a header followed by a small
+A routing message consists of a header that may be followed by a
 number of
 .Vt sockaddr
-structures (which are variable length),
-interpreted by position, and delimited
-by the length entry in the
-.Vt sockaddr .
+structures of a variable size (the size of a particular structure
+is determined by its
+.Vt sa_len
+entry; every structure is aligned on the boundary of sizeof(long)).
 An example of a message with four addresses might be an
 IPv4 route addition: the destination, netmask, gateway, and label,
 since both netmasks and labels are sent over the routing socket as
@@ -477,6 +477,119 @@ Specifiers for which addresses are prese
 #define RTA_SRC0x100   /* source sockaddr present */
 #define RTA_SRCMASK0x200   /* source netmask present */
 #define RTA_LABEL  0x400   /* route label present */
+.Ed
+.Sh EXAMPLES
+Parsing a routing message.
+.Bd -literal
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* An abstraction of a routing message. */
+union rt_msg {
+   struct rt_msghdr rt;
+   struct if_msghdr ifm;
+   struct ifa_msghdr ifa;
+   struct if_announcemsghdr ifan;
+   uint8_t buf [ RTM_MAXSIZE ];
+};
+
+#define rt_msglen rt.rtm_msglen
+#define rt_version rt.rtm_version
+#define rt_type rt.rtm_type
+#define rt_hdrlen rt.rtm_hdrlen
+#define rt_buf buf
+
+/* Round up the size of a struct sockaddr as required by route(4). */
+#define ROUNDUP(x) (1 + (((x) - 1) | (sizeof(long) - 1)))
+
+/* Parse address structures that may follow the header. */
+
+static union rt_msg *
+rt_msg_parse_addrs (union rt_msg * const msg, const int addrs)
+{
+   const void *p = (void *) msg + msg->rt_hdrlen;
+   const void * const q  = (void *) msg + msg->rt_msglen;
+   int mask = addrs;
+
+   while (p < q && mask ) {
+   const struct sockaddr * const sa = p;
+   const int rta = mask ^ (mask & mask - 1);
+
+   /*
+* Here the variable `sa' points to the current sockadr
+* and the variable `rta' holds the corresponding
+* RTA_ value.
+*
+* NOTE: Before using these variables, you MUST validate
+* that (a) the value of `rta' is defined and expected;
+* (b) `sa_len' of `sa' must correspond to its `sa_family'.
+*/
+
+   p += ROUNDUP (sa->sa_len);
+   mask &= ~rta;
+   }
+
+   if (mask)
+   warn ("A route(4) message is missing (some) addresses.");
+
+   if (p < q)
+   warn ("A route(4) message contains odd data.");
+
+   if (p > q) {
+   err (4, "A route(4) message is malformed.");
+   return NULL;
+   }
+
+   return msg;
+}
+
+/* Parse a message. */
+
+static union rt_msg *
+rt_msg_parse ( union rt_msg * const msg )
+{
+   int addrs = 0;
+
+   if (msg -> rt_version != RTM_VERSION ) {
+   err (4, "Unexpected version of a route(4) message: %d",
+   msg->rt_version);
+   return NULL;
+   }
+
+   switch (msg -> rt_type) {
+   case RTM_ADD:
+   case RTM_DELETE:
+   case RTM_CHANGE:
+   case RTM_GET:
+   case RTM_LOSING:
+   case RTM_REDIRECT:
+   case RTM_MISS:
+   case RTM_RESOLVE:
+   case RTM_DESYNC:
+   addrs = msg->rt.rtm_addrs;
+   break;
+   case RTM_NEWADDR:
+   case RTM_DELADDR:
+   addrs = msg->ifa.ifam_addrs;
+   break;
+   case RTM_IFINFO:
+   addrs = msg->ifm.ifm_addrs;
+   break;
+   case RTM_IFANNOUNCE:
+   return msg;
+   case RTM_INVALIDATE:
+   err (4, "RTM_INVALIDATE received from route(4).");
+   return NULL;
+   default:
+   warn ("Unknown route(4) message: %d", msg->rt_type );
+   return NULL;
+   }
+
+   return rt_msg_parse_addrs (msg, addrs);
+}
 .Ed
 .Sh SEE ALSO
 .Xr netstat 1 ,



Re: route(4) manual and sockaddrs; ROUNDUP()

2019-07-14 Thread Vadim Penzin

Since `sa_len' describes the size of a `sockaddr' (or one of its
derivatives) /including/ `sa_len' (maybe I am wrong, but this is my
interpretation of the comment `total length' that appears near the
definition of `struct sockaddr' in ), `sa_len' just
cannot be zero.


Yes, it can not be zero.
  

The current definition of ROUNDUP() might hide a bug.  In addition, on
some machines, it disturbs the pipeline of the CPU by introducing a
branch (for no real reason, as it seems, while I might be
nitpicking). At very least, it looks confusing.


The following patch amends the issue:

Index: route.c
===
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.387
diff -u -p -r1.387 route.c
--- route.c 24 Jun 2019 22:26:25 -  1.387
+++ route.c 14 Jul 2019 10:05:04 -
@@ -138,7 +138,7 @@
 #include 
 #endif

-#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : 
sizeof(long))

+#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))

 /* Give some jitter to hash, to avoid synchronization between routers. */
 static uint32_trt_hashjitter;



Qt5's libtool link scripts are unusable

2019-06-20 Thread Vadim Penzin
I admit that I am not familiar with the release process of pre-built 
binary packages; I might be writing to a wrong mailing list and I 
apologize in advance.


All libtool scripts from qt5 (/usr/local/lib/qt5/*.la) contain the 
following on their third line:


  LIBQt5XXX_VERSION=5.9# The name that we can dlopen(3).

(XXX above stands for the name of a particular library, such as Core, 
Network, etc.)


Since shell scripts (that libtool generates) source .la files, sh(1) 
fails on unexpected '(' because someone, somewhere omitted a space 
before the comment.


Patching /usr/local/lib/qt5/*.la files programmatically by tucking a 
space before the hash character brings linking with Qt5 assisted 
(encumbered?) by libtool back to life.


--Vadim



Re: route(4) manual and sockaddrs; ROUNDUP()

2019-04-27 Thread Vadim Penzin

Well, the manual shall tell the truth, whatever it is:

Messages are formed by a header followed by a small number of
sockaddr structures of variable length. The size of every
sockaddr structure can be computed by rounding the value of the
`sa_len' field of the current structure up to sizeof(long)
bytes.

I provided a reference to the code in question in my original message:


It took me some time to figure out that, apparently, I am looking at
the combined effect of in_socktrim() (see src/sys/netinet/in.c) and
ROUNDUP() (see src/sys/net/rtsock.c) applied to the netmask of
0xff00 that was stored as sockaddr_in'.


The following is a more precise description of its location:

See 
https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/net/rtsock.c?annotate=1.285


The macro ROUNDUP is defined on lines 1347-1348
It is also used in the definition of the macro ADVANCE on line 1349
The first direct use of ROUNDUP that I quoted is on line 1431.
The second is on line 1476.

--Vadim

On 4/26/19 6:14 PM, Claudio Jeker wrote:

On Fri, Apr 26, 2019 at 01:55:52PM +0300, Vadim Penzin wrote:

Greetings,


1. The manual of route(4) explains the structure of its messages thus:

 `Messages are formed by a header followed by a small number of
 sockaddr structures (which are variable length), interpreted by
 position, and delimited by the length entry in the sockaddr.'

(That phrase is quite unfortunate in itself: `sa_len' is supposed to
/determine/ the length of a structure.  To me, the word `delimited'
implies the presence of a memory object between two adjacent
structures, which certainly was not the intent of the author.)


Yes this is not quite right since the lenght is rounded to the next long
word to ensure that structures are properly aligned on strict align
architectures.
  

Armed with that knowledge, I wrote a parser the other day.  I very
much enjoyed OpenBSD until my program fatally stumbled on a peculiar
structure that does not fit the above description:

 05 00 00 00 ff 00 00 00

(The value of `sa_len' of that `sockaddr' is nothing that I am
familiar with, the address family is `AF_UNSPEC', and the most
disturbing: `sa_len' does not match the physical size of this
structure. These eight bytes were immediately followed by a perfectly
valid `sockaddr_in'.)


This is a probably a netmask which are special in many senses from the old
time of the radix routing tree. For AF_UNSPEC it defines how many bytes
are used to store the netmask. It is wierd I agree.
  

It took me some time to figure out that, apparently, I am looking at
the combined effect of in_socktrim() (see src/sys/netinet/in.c) and
ROUNDUP() (see src/sys/net/rtsock.c) applied to the netmask of
0xff00 that was stored as sockaddr_in'.

I believe that manuals should be more merciful.  In the absence of
proper documentation, the part of my program that handles this case looks
like a mysterious ritual; it should not be that way.
  
Please send suggestions to better documentation to this list.

route(4) is not perfect for sure and could use some work.
  

2. The definition of ROUNDUP() somewhat surprised me: it silently handles
zero. The macro is local to the compilation unit; it is used
this way:

 if (rtinfo == NULL || (sa = rtinfo->rti_info[i]) == NULL)
continue;
rtinfo->rti_addrs |= (1 << i);
dlen = ROUNDUP(sa->sa_len);

and this way:

if ((sa = rtinfo->rti_info[i]) == NULL)
 continue;
rtinfo->rti_addrs |= (1 << i);
dlen = ROUNDUP(sa->sa_len);


What code are you talking about?
  

(In the second case, the programmer does not check `rtinfo' for being
NULL.  I only hope that there exists a good explanation to that.)

Since `sa_len' describes the size of a `sockaddr' (or one of its
derivatives) /including/ `sa_len' (maybe I am wrong, but this is my
interpretation of the comment `total length' that appears near the
definition of `struct sockaddr' in ), `sa_len' just
cannot be zero.


Yes, it can not be zero.
  

The current definition of ROUNDUP() might hide a bug.  In addition, on
some machines, it disturbs the pipeline of the CPU by introducing a
branch (for no real reason, as it seems, while I might be
nitpicking). At very least, it looks confusing.







route(4) manual and sockaddrs; ROUNDUP()

2019-04-26 Thread Vadim Penzin

Greetings,


1. The manual of route(4) explains the structure of its messages thus:

`Messages are formed by a header followed by a small number of
sockaddr structures (which are variable length), interpreted by
position, and delimited by the length entry in the sockaddr.'

(That phrase is quite unfortunate in itself: `sa_len' is supposed to
/determine/ the length of a structure.  To me, the word `delimited'
implies the presence of a memory object between two adjacent
structures, which certainly was not the intent of the author.)

Armed with that knowledge, I wrote a parser the other day.  I very
much enjoyed OpenBSD until my program fatally stumbled on a peculiar
structure that does not fit the above description:

05 00 00 00 ff 00 00 00

(The value of `sa_len' of that `sockaddr' is nothing that I am
familiar with, the address family is `AF_UNSPEC', and the most
disturbing: `sa_len' does not match the physical size of this
structure. These eight bytes were immediately followed by a perfectly
valid `sockaddr_in'.)

It took me some time to figure out that, apparently, I am looking at
the combined effect of in_socktrim() (see src/sys/netinet/in.c) and
ROUNDUP() (see src/sys/net/rtsock.c) applied to the netmask of
0xff00 that was stored as sockaddr_in'.

I believe that manuals should be more merciful.  In the absence of
proper documentation, the part of my program that handles this case 
looks like a mysterious ritual; it should not be that way.



2. The definition of ROUNDUP() somewhat surprised me: it silently 
handles zero. The macro is local to the compilation unit; it is used

this way:

if (rtinfo == NULL || (sa = rtinfo->rti_info[i]) == NULL)
continue;
rtinfo->rti_addrs |= (1 << i);
dlen = ROUNDUP(sa->sa_len);

and this way:

if ((sa = rtinfo->rti_info[i]) == NULL)
continue;
rtinfo->rti_addrs |= (1 << i);
dlen = ROUNDUP(sa->sa_len);

(In the second case, the programmer does not check `rtinfo' for being
NULL.  I only hope that there exists a good explanation to that.)

Since `sa_len' describes the size of a `sockaddr' (or one of its
derivatives) /including/ `sa_len' (maybe I am wrong, but this is my
interpretation of the comment `total length' that appears near the
definition of `struct sockaddr' in ), `sa_len' just
cannot be zero.

The current definition of ROUNDUP() might hide a bug.  In addition, on
some machines, it disturbs the pipeline of the CPU by introducing a
branch (for no real reason, as it seems, while I might be
nitpicking). At very least, it looks confusing.


Thank you for your time,
-- Vadim