Re: Properly check if ACPI devices are enabled

2022-01-27 Thread Mike Larkin
On Mon, Jan 24, 2022 at 12:15:58PM -0800, Philip Guenther wrote:
> On Mon, Jan 24, 2022 at 11:41 AM Mark Kettenis 
> wrote:
>
> > > Date: Mon, 24 Jan 2022 20:19:46 +0100
> > > From: Anton Lindqvist 
> > >
> > > On Mon, Jan 24, 2022 at 05:31:49PM +0100, Mark Kettenis wrote:
> > > > Currently we attach ACPI devices that are present in a machine.
> > > > However, in some cases ACPI devices can be present, but not enabled.
> > > > Attaching a device driver to devices that are not enabled is not a
> > > > good idea since reading and writing from/to its registers will fail
> > > > and the driver will malfunction in interesting ways.  Such as a com(4)
> > > > serial port that is misdetected and hangs the kernel when it is
> > > > actually opened.
> > > >
> > > > The diff below makes sure we only enable devices that are actually
> > > > enabled.  This may cause some devices to disappear in OpenBSD.
> > > > However those devices should have been unusable anyway, so that isn't
> > > > an issue.
> > > >
> > > > ok?
> > >
> > > According to the ACPI specification[1]:
> > >
> > > > A device can only decode its hardware resources if both bits 0 and 1
> > are
> > > > set. If the device is not present (bit [0] cleared) or not enabled (bit
> > > > [1] cleared), then the device must not decode its resources.
> >
> > Just before that it says:
> >
> >   If bit [0] is cleared, then bit 1 must also be cleared (in other
> >   words, a device that is not present cannot be enabled).
> >
> > > Should we therefore check for presence of both STA_PRESENT and
> > > STA_ENABLED?
> >
> > So according to the ACPI specification we don't need to do that.
> > Should we do it just to be safe?
> >
>
> Unless you're taking money bets about this being the one thing in the ACPI
> spec that some vendor won't screw up, doing both seems "can't be worse; can
> be better".
>
> Philip

A bit late to the party here, but we should all remember the HP bios with the
FACS table version of "1" and not 1.  (0x31 and not 0x01).

So yes, someone will indeed screw it up if it's possible to screw it up.



Re: touch(1): don't leak descriptor if futimens(2) fails

2022-01-27 Thread Philip Guenther
On Thu, Jan 27, 2022 at 4:03 PM Scott Cheloha 
wrote:

> If futimens(2) fails here then close(2) is not called and we leak the
> descriptor.
>

Good catch.


I think futimens(2) and close(2) failures are exotic enough to warrant
> printing the system call name.
>

I don't understand this.  Can you give an example of an error message that
touch currently might emit where knowing that the failed call was
futimens() or close() would affect the analysis of how to deal with it?  I
mean, it looks like the only errors that futimens() could really return are
EROFS, EIO, and EPERM (implies a race by different users to create the
file), and close() could only return EIO.  For any of those errors, you're
going to handle them the same whether they're from open, futimens, or
close, no?


Philip Guenther


touch(1): don't leak descriptor if futimens(2) fails

2022-01-27 Thread Scott Cheloha
If futimens(2) fails here then close(2) is not called and we leak the
descriptor.

I think futimens(2) and close(2) failures are exotic enough to warrant
printing the system call name.

ok?

Index: touch.c
===
RCS file: /cvs/src/usr.bin/touch/touch.c,v
retrieving revision 1.26
diff -u -p -r1.26 touch.c
--- touch.c 10 Mar 2019 15:11:52 -  1.26
+++ touch.c 27 Jan 2022 23:55:50 -
@@ -137,9 +137,18 @@ main(int argc, char *argv[])
 
/* Create the file. */
fd = open(*argv, O_WRONLY | O_CREAT, DEFFILEMODE);
-   if (fd == -1 || futimens(fd, ts) || close(fd)) {
+   if (fd == -1) {
rval = 1;
warn("%s", *argv);
+   continue;
+   }
+   if (futimens(fd, ts) == -1) {
+   warn("futimens %s", *argv);
+   rval = 1;
+   }
+   if (close(fd) == -1) {
+   warn("close %s", *argv);
+   rval = 1;
}
}
return rval;



mention rpki-client(8) on openbgpd/index.html

2022-01-27 Thread Daniel Jakots
Hi,

I think rpki-client is now an important piece of the DFZ, so it makes
sense to mention it.

Comments? OK?

BTW there's no mention of eigrpd, should we add it? Or there's no need
to list them all?

Cheers,
Daniel

Index: index.html
===
RCS file: /cvs/www/openbgpd/index.html,v
retrieving revision 1.61
diff -u -p -r1.61 index.html
--- index.html  5 Nov 2021 00:38:58 -   1.61
+++ index.html  27 Jan 2022 23:41:09 -
@@ -64,6 +64,8 @@ OpenBGPD's companions,
 add support for the respective protocols.
 https://man.openbsd.org/ldpd;>ldpd(8) and
 https://man.openbsd.org/mpe;>mpe(4) add MPLS support.
+https://man.openbsd.org/rpki-client;>rpki-client(8) facilitates
+validation of the Route Origin of a BGP announcement.
 
 
 OpenBGPD is primarily developed by Henning Brauer, Peter Hessler, and



kubsan nd6

2022-01-27 Thread Alexander Bluhm
Hi,

kubsan: netinet6/nd6.c:948:42: type mismatch: member access within null pointer 
of type 'struct in6_ifaddr'
kubsan: netinet6/nd6_nbr.c:640:43: type mismatch: member access within null 
pointer of type 'struct in6_ifaddr'

This codes works as ifaddr ia_ifa is the first field of in6_ifaddr.
So the pointers are the same, and one NULL check works for both.
But in ISO C NULL has a type and this is undefined behavior.  So
add a second NULL check that the compiler can optimize away.  The
resulting assembler is the same.

ok?

bluhm

Index: netinet6/nd6.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.236
diff -u -p -r1.236 nd6.c
--- netinet6/nd6.c  7 Nov 2021 19:38:25 -   1.236
+++ netinet6/nd6.c  27 Jan 2022 22:20:06 -
@@ -792,6 +792,7 @@ nd6_rtrequest(struct ifnet *ifp, int req
struct sockaddr *gate = rt->rt_gateway;
struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;
struct ifaddr *ifa;
+   struct in6_ifaddr *ifa6;
 
if (ISSET(rt->rt_flags, RTF_GATEWAY|RTF_MULTICAST|RTF_MPLS))
return;
@@ -944,8 +945,9 @@ nd6_rtrequest(struct ifnet *ifp, int req
 * check if rt_key(rt) is one of my address assigned
 * to the interface.
 */
-   ifa = _ifpwithaddr(ifp,
-   (rt_key(rt))->sin6_addr)->ia_ifa;
+   ifa6 = in6ifa_ifpwithaddr(ifp,
+   (rt_key(rt))->sin6_addr);
+   ifa = ifa6 ? >ia_ifa : NULL;
if (ifa) {
ln->ln_state = ND6_LLINFO_REACHABLE;
ln->ln_byhint = 0;
Index: netinet6/nd6_nbr.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.130
diff -u -p -r1.130 nd6_nbr.c
--- netinet6/nd6_nbr.c  13 Dec 2021 14:30:16 -  1.130
+++ netinet6/nd6_nbr.c  27 Jan 2022 22:20:06 -
@@ -568,6 +568,7 @@ nd6_na_input(struct mbuf *m, int off, in
char *lladdr = NULL;
int lladdrlen = 0;
struct ifaddr *ifa;
+   struct in6_ifaddr *ifa6;
struct llinfo_nd6 *ln;
struct rtentry *rt = NULL;
struct sockaddr_dl *sdl;
@@ -637,7 +638,8 @@ nd6_na_input(struct mbuf *m, int off, in
lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
}
 
-   ifa = _ifpwithaddr(ifp, )->ia_ifa;
+   ifa6 = in6ifa_ifpwithaddr(ifp, );
+   ifa = ifa6 ? >ia_ifa : NULL;
 
/*
 * Target address matches one of my interface address.
Index: arch/amd64/conf/GENERIC
===
RCS file: /data/mirror/openbsd/cvs/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.510
diff -u -p -r1.510 GENERIC
--- arch/amd64/conf/GENERIC 4 Jan 2022 05:50:43 -   1.510
+++ arch/amd64/conf/GENERIC 27 Jan 2022 22:19:55 -
@@ -381,23 +381,23 @@ wsmouse*  at pms? mux 0
 #mmuagp*   at pchb?# amd64 mmu agp.
 #agp*  at mmuagp?
 
-inteldrm*  at pci? # Intel i915, i945 DRM driver
-intagp*at inteldrm?
-agp*   at intagp?
-drm0   at inteldrm? primary 1
-drm*   at inteldrm?
-wsdisplay0 at inteldrm? primary 1
-wsdisplay* at inteldrm? mux -1
-radeondrm* at pci? # ATI Radeon DRM driver
-drm0   at radeondrm? primary 1
-drm*   at radeondrm?
-wsdisplay0 at radeondrm? primary 1
-wsdisplay* at radeondrm? mux -1
-amdgpu*at pci?
-drm0   at amdgpu? primary 1
-drm*   at amdgpu?
-wsdisplay0 at amdgpu? primary 1
-wsdisplay* at amdgpu? mux -1
+#inteldrm* at pci? # Intel i915, i945 DRM driver
+#intagp*   at inteldrm?
+#agp*  at intagp?
+#drm0  at inteldrm? primary 1
+#drm*  at inteldrm?
+#wsdisplay0at inteldrm? primary 1
+#wsdisplay*at inteldrm? mux -1
+#radeondrm*at pci? # ATI Radeon DRM driver
+#drm0  at radeondrm? primary 1
+#drm*  at radeondrm?
+#wsdisplay0at radeondrm? primary 1
+#wsdisplay*at radeondrm? mux -1
+#amdgpu*   at pci?
+#drm0  at amdgpu? primary 1
+#drm*  at amdgpu?
+#wsdisplay0at amdgpu? primary 1
+#wsdisplay*at amdgpu? mux -1
 
 pcppi0 at isa?
 
Index: arch/amd64/conf/GENERIC.MP
===
RCS file: /data/mirror/openbsd/cvs/src/sys/arch/amd64/conf/GENERIC.MP,v
retrieving revision 1.16
diff -u -p -r1.16 GENERIC.MP
--- arch/amd64/conf/GENERIC.MP  9 Feb 2021 14:06:19 -   1.16
+++ arch/amd64/conf/GENERIC.MP  27 Jan 2022 22:19:55 -
@@ -5,5 +5,6 @@ include "arch/amd64/conf/GENERIC"
 option MULTIPROCESSOR
 #optionMP_LOCKDEBUG
 #optionWITNESS
+option KUBSAN
 
 cpu*   at mainbus?



amd64: simplify TSC sync testing

2022-01-27 Thread Scott Cheloha
Hi,

sthen@ complained recently about a multisocket system not being able
to use the TSC in userspace because the sync test measured too much
skew and disabled it.

I don't think there is any real skew on that system.  I think the sync
test is confusing NUMA overhead for skew and issuing a false positive
result.

Now, we _could_ change the test to account for NUMA overhead.  I don't
know exactly how you would do it, but I imagine you could devise a
handshake to compute an estimate and then factor that into your skew
measurement.

Another approach is to drop the current skew measurement handshake in
favor of a dumber approach without that particular false positive case.

This patch changes our sync test to a dumber approach.  Instead of
trying to measure and correct for skew we only test for lag and do
not attempt to correct for it if we detect it.

Two CPUs enter a loop and continuously check whether the other CPU's
TSC lags their own.  With this approach the false positive we are
seeing on sthen@'s machine is impossible because we are only checking
whether one value lags the other, not whether their difference exceeds
an arbitrary value.  Synchronization is tested to within a margin of
error because both CPUs are checking for lag at the same time.

To keep the margin of error is as small as possible for a given clock
rate we spin for a relatively long time.  Right now we spin for 1
millisecond per test round.  This is arbitrary but it seems to work.
There is a point of diminishing returns for round duration.  This
sync test approach takes much more time than the current handshake
approach and I'd like to minimize our impact on boot time.

To actually shrink the margin of error you need to run the CPUs at the
highest possible clock rate.  If they are underclocked due to e.g.
SpeedStep your margin of error grows and the test may fail to detect
lag.

We do two rounds of testing for each CPU.  This is arbitrary.  You
could do more.  I think at least one additional test round is a good
idea, just in case we "get lucky" in the first round.  I think this
could help mitigate measurement problems introduced by factors beyond
our control.  For example, if one of the CPUs blacks out for the
duration of the test because it is preempted by the hypervisor the
test will pass but the result is bogus.  If we do more test rounds we
have a better chance of getting a meaningful result even if we get
unlucky with hypervisor preemption or something similar.

Misc. notes:

- We no longer have a per-CPU skew value.  If any TSC lags another we
  just set the timecounter quality to a negative number.  We don't
  disable userspace or attempt to correct the skew in the kernel.

  I think that bears repeating: we are no longer correcting the skew.
  If we detect any lag the TSC is effectively broken.

- There is no longer any concept of TSC drift.  Drift is computed
  from skew change and we have no skew value anymore.

- Am I allowed to printf(9) from a secondary CPU during boot?  It
  seems to hang the kernel but I don't know why.

- I have no idea how to use the volatile keyword correctly.  I am
  trying to keep the compiler from optimizing away my stores.  I don't
  think it implicitly understands that two threads are looking at these
  variables at the same time

  If I am abusing it please tell me.  I'm trying to avoid a situation
  where some later compiler change subtly breaks the test.  If I
  sprinkle volatile everywhere my impression is that it forces the
  compiler to actually do the store.

- I have aligned the global TSC values to 64 bytes to try to minimize
  "cache bounce".  Each value has one reader and one writer so if the
  two values are on different cache lines a write to one value shouldn't
  cause a cache miss for the writer of the other value.

  ... right?

  I'm not an expert on cache stuff.  Can someone shed light on whether
  I am doing the right thing here?

- I rolled my own thread barriers for the test.  Would a generic
  thread barrier be useful elsewhere in the kernel?  Feels wrong to roll
  my own synchronization primitive, but maybe we actually don't need
  them anywhere else?

- I would like to forcibly reset IA32_TSC_ADJUST before running the
  test but I don't think the CPU feature flags are set early enough
  for tsc_reset_adjust() to see the relevant flag even if the CPU
  has that register.

  Could we initialize the flags earlier in boot, before the sync test?

Testing notes:

- Tests on multisocket systems, multiprocessor VMs on various hypervisors,
  and on systems where the TSC is currently disabled by the kernel are
  appreciated!  Just send your dmesg.

- TSC_DEBUG is set for now to force the test to run on all CPUs even if
  a prior test has already failed.  This is useful for testing but in
  practice if we fail one test there is no point in running further
  tests.

  I'm actually unsure about this.  If we take the time to run the test
  on every processor it might give us a better 

Re: passwd(1) does not need librpcsvc

2022-01-27 Thread Benjamin Baier
On Thu, 27 Jan 2022 15:17:01 +
Miod Vallat  wrote:

> > Hi,
> > 
> > linking with librpcsvc should be superfluous now.
> 
> Then you should also update DPADD to remove $(LIBRPCSVC}...
> 
Patch V2

Index: Makefile
===
RCS file: /var/cvs/src/usr.bin/passwd/Makefile,v
retrieving revision 1.41
diff -u -p -r1.41 Makefile
--- Makefile26 Nov 2015 19:01:47 -  1.41
+++ Makefile27 Jan 2022 16:20:05 -
@@ -6,8 +6,8 @@ PROG=   passwd
 SRCS=  local_passwd.c passwd.c getpwent.c \
pwd_check.c
 .PATH:  ${.CURDIR}/../../lib/libc/gen
-DPADD+= ${LIBRPCSVC} ${LIBUTIL}
-LDADD+= -lrpcsvc -lutil
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
 CFLAGS+= -I${.CURDIR}
 
 CFLAGS+=-I${.CURDIR}/../../lib/libc/include



Re: head(1): refactor main loop

2022-01-27 Thread Allen Smith
From:

https://en.cppreference.com/w/c/language/main_function
argv-   Pointer to the first element of an array of argc + 1 pointers, 
of which the last one is null and the previous ones, if any, point to strings 
that represent the arguments passed to the program from the host environment. 
If argv[0] is not a null pointer (or, equivalently, if argc > 0), it points to 
a string that represents the program name, which is empty if the program name 
is not available from the host environment.

There are other programs like /usr/src/bin/echo/echo.c that take advantage of 
this behavior.

Cheers,
-Allen


From: owner-t...@openbsd.org  on behalf of flint pyrite 

Sent: Thursday, January 27, 2022 8:31 AM
To: Scott Cheloha 
Cc: tech@openbsd.org 
Subject: Re: head(1): refactor main loop

+   for (; *argv != NULL; argv++)

is argv[1] guaranteed? I have never seen this before.

On Wed, Jan 26, 2022 at 9:52 PM Scott Cheloha 
wrote:

> The main loop in head(1) is obfuscated.  In particular, the path
> through the loop to exit(3) is extremely clever.  Clever in a bad way.
>
> This patch moves the open/read/write/close portions of the loop out
> into a separate function, head_file().  I think the result is easier
> to understand.  We only loop in main() if we have file arguments, the
> argv[] loop is idiomatic and simple, we actually reach the end of
> main(), etc.
>
> In a subsequent patch I intend to switch to getline(3) and add more
> error checking to head_file().  For now I have just moved the
> getc/putchar loop into head_file() as-is.
>
> ok?
>
> Index: head.c
> ===
> RCS file: /cvs/src/usr.bin/head/head.c,v
> retrieving revision 1.22
> diff -u -p -r1.22 head.c
> --- head.c  10 Oct 2021 15:57:25 -  1.22
> +++ head.c  27 Jan 2022 04:41:09 -
> @@ -37,6 +37,7 @@
>  #include 
>  #include 
>
> +int head_file(const char *, long, int);
>  static void usage(void);
>
>  /*
> @@ -49,9 +50,7 @@ int
>  main(int argc, char *argv[])
>  {
> const char *errstr;
> -   FILE*fp;
> -   longcnt;
> -   int ch, firsttime;
> +   int ch;
> longlinecnt = 10;
> int status = 0;
>
> @@ -81,33 +80,46 @@ main(int argc, char *argv[])
> }
> argc -= optind, argv += optind;
>
> -   for (firsttime = 1; ; firsttime = 0) {
> -   if (!*argv) {
> -   if (!firsttime)
> -   exit(status);
> -   fp = stdin;
> -   if (pledge("stdio", NULL) == -1)
> -   err(1, "pledge");
> -   } else {
> -   if ((fp = fopen(*argv, "r")) == NULL) {
> -   warn("%s", *argv++);
> -   status = 1;
> -   continue;
> -   }
> -   if (argc > 1) {
> -   if (!firsttime)
> -   putchar('\n');
> -   printf("==> %s <==\n", *argv);
> -   }
> -   ++argv;
> -   }
> -   for (cnt = linecnt; cnt && !feof(fp); --cnt)
> -   while ((ch = getc(fp)) != EOF)
> -   if (putchar(ch) == '\n')
> -   break;
> -   fclose(fp);
> +   if (argc == 0) {
> +   if (pledge("stdio", NULL) == -1)
> +   err(1, "pledge");
> +
> +   status = head_file(NULL, linecnt, 0);
> +   } else {
> +   for (; *argv != NULL; argv++)
> +   status |= head_file(*argv, linecnt, argc > 1);
> }
> -   /*NOTREACHED*/
> +
> +   return status;
> +}
> +
> +int
> +head_file(const char *path, long count, int need_header)
> +{
> +   FILE *fp;
> +   int ch;
> +   static int first = 1;
> +
> +   if (path != NULL) {
> +   fp = fopen(path, "r");
> +   if (fp == NULL) {
> +   warn("%s", path);
> +   return 1;
> +   }
> +   if (need_header) {
> +   printf("%s==> %s <==\n", first ? "" : "\n", path);
> +   first = 0;
> +   }
> +   } else
> +   fp = stdin;
> +
> +   for (; count > 0 && !feof(fp); --count)
> +   while ((ch = getc(fp)) != EOF)
> +   if (putchar(ch) == '\n')
> +   break;
> +   fclose(fp);
> +
> +   return 0;
>  }
>
>
>
>


Re: head(1): refactor main loop

2022-01-27 Thread flint pyrite
+   for (; *argv != NULL; argv++)

is argv[1] guaranteed? I have never seen this before.

On Wed, Jan 26, 2022 at 9:52 PM Scott Cheloha 
wrote:

> The main loop in head(1) is obfuscated.  In particular, the path
> through the loop to exit(3) is extremely clever.  Clever in a bad way.
>
> This patch moves the open/read/write/close portions of the loop out
> into a separate function, head_file().  I think the result is easier
> to understand.  We only loop in main() if we have file arguments, the
> argv[] loop is idiomatic and simple, we actually reach the end of
> main(), etc.
>
> In a subsequent patch I intend to switch to getline(3) and add more
> error checking to head_file().  For now I have just moved the
> getc/putchar loop into head_file() as-is.
>
> ok?
>
> Index: head.c
> ===
> RCS file: /cvs/src/usr.bin/head/head.c,v
> retrieving revision 1.22
> diff -u -p -r1.22 head.c
> --- head.c  10 Oct 2021 15:57:25 -  1.22
> +++ head.c  27 Jan 2022 04:41:09 -
> @@ -37,6 +37,7 @@
>  #include 
>  #include 
>
> +int head_file(const char *, long, int);
>  static void usage(void);
>
>  /*
> @@ -49,9 +50,7 @@ int
>  main(int argc, char *argv[])
>  {
> const char *errstr;
> -   FILE*fp;
> -   longcnt;
> -   int ch, firsttime;
> +   int ch;
> longlinecnt = 10;
> int status = 0;
>
> @@ -81,33 +80,46 @@ main(int argc, char *argv[])
> }
> argc -= optind, argv += optind;
>
> -   for (firsttime = 1; ; firsttime = 0) {
> -   if (!*argv) {
> -   if (!firsttime)
> -   exit(status);
> -   fp = stdin;
> -   if (pledge("stdio", NULL) == -1)
> -   err(1, "pledge");
> -   } else {
> -   if ((fp = fopen(*argv, "r")) == NULL) {
> -   warn("%s", *argv++);
> -   status = 1;
> -   continue;
> -   }
> -   if (argc > 1) {
> -   if (!firsttime)
> -   putchar('\n');
> -   printf("==> %s <==\n", *argv);
> -   }
> -   ++argv;
> -   }
> -   for (cnt = linecnt; cnt && !feof(fp); --cnt)
> -   while ((ch = getc(fp)) != EOF)
> -   if (putchar(ch) == '\n')
> -   break;
> -   fclose(fp);
> +   if (argc == 0) {
> +   if (pledge("stdio", NULL) == -1)
> +   err(1, "pledge");
> +
> +   status = head_file(NULL, linecnt, 0);
> +   } else {
> +   for (; *argv != NULL; argv++)
> +   status |= head_file(*argv, linecnt, argc > 1);
> }
> -   /*NOTREACHED*/
> +
> +   return status;
> +}
> +
> +int
> +head_file(const char *path, long count, int need_header)
> +{
> +   FILE *fp;
> +   int ch;
> +   static int first = 1;
> +
> +   if (path != NULL) {
> +   fp = fopen(path, "r");
> +   if (fp == NULL) {
> +   warn("%s", path);
> +   return 1;
> +   }
> +   if (need_header) {
> +   printf("%s==> %s <==\n", first ? "" : "\n", path);
> +   first = 0;
> +   }
> +   } else
> +   fp = stdin;
> +
> +   for (; count > 0 && !feof(fp); --count)
> +   while ((ch = getc(fp)) != EOF)
> +   if (putchar(ch) == '\n')
> +   break;
> +   fclose(fp);
> +
> +   return 0;
>  }
>
>
>
>


Re: rev(1): refactor main loop

2022-01-27 Thread Todd C . Miller
On Thu, 27 Jan 2022 08:52:52 -0600, Scott Cheloha wrote:

> Just like with head(1), rev(1)'s main loop is obfuscated.
>
> This patch moves the open/read/write/close portion of the main loop
> out of main() into a separate function, rev_file().  "multibyte"
> becomes a global.

OK millert@

 - todd



Re: head(1): refactor main loop

2022-01-27 Thread Todd C . Miller
On Wed, 26 Jan 2022 22:50:27 -0600, Scott Cheloha wrote:

> The main loop in head(1) is obfuscated.  In particular, the path
> through the loop to exit(3) is extremely clever.  Clever in a bad way.
>
> This patch moves the open/read/write/close portions of the loop out
> into a separate function, head_file().  I think the result is easier
> to understand.  We only loop in main() if we have file arguments, the
> argv[] loop is idiomatic and simple, we actually reach the end of
> main(), etc.

OK millert@

 - todd



Re: passwd(1) does not need librpcsvc

2022-01-27 Thread Miod Vallat
> Hi,
> 
> linking with librpcsvc should be superfluous now.

Then you should also update DPADD to remove $(LIBRPCSVC}...

> Index: Makefile
> ===
> RCS file: /var/cvs/src/usr.bin/passwd/Makefile,v
> retrieving revision 1.41
> diff -u -p -r1.41 Makefile
> --- Makefile  26 Nov 2015 19:01:47 -  1.41
> +++ Makefile  27 Jan 2022 14:59:09 -
> @@ -7,7 +7,7 @@ SRCS= local_passwd.c passwd.c getpwent.c
>   pwd_check.c
>  .PATH:  ${.CURDIR}/../../lib/libc/gen
>  DPADD+= ${LIBRPCSVC} ${LIBUTIL}
> -LDADD+= -lrpcsvc -lutil
> +LDADD+= -lutil
>  CFLAGS+= -I${.CURDIR}
>  
>  CFLAGS+=-I${.CURDIR}/../../lib/libc/include
> 
> --
> Greetings Ben
> 



passwd(1) does not need librpcsvc

2022-01-27 Thread Benjamin Baier
Hi,

linking with librpcsvc should be superfluous now.

Index: Makefile
===
RCS file: /var/cvs/src/usr.bin/passwd/Makefile,v
retrieving revision 1.41
diff -u -p -r1.41 Makefile
--- Makefile26 Nov 2015 19:01:47 -  1.41
+++ Makefile27 Jan 2022 14:59:09 -
@@ -7,7 +7,7 @@ SRCS=   local_passwd.c passwd.c getpwent.c
pwd_check.c
 .PATH:  ${.CURDIR}/../../lib/libc/gen
 DPADD+= ${LIBRPCSVC} ${LIBUTIL}
-LDADD+= -lrpcsvc -lutil
+LDADD+= -lutil
 CFLAGS+= -I${.CURDIR}
 
 CFLAGS+=-I${.CURDIR}/../../lib/libc/include

--
Greetings Ben



rev(1): refactor main loop

2022-01-27 Thread Scott Cheloha
Just like with head(1), rev(1)'s main loop is obfuscated.

This patch moves the open/read/write/close portion of the main loop
out of main() into a separate function, rev_file().  "multibyte"
becomes a global.

I think the result is easier to understand at a glance.

In a subsequent patch I want to drop the "rpath" promise in the
no-file branch, but that needs to wait.

ok?

Index: rev.c
===
RCS file: /cvs/src/usr.bin/rev/rev.c,v
retrieving revision 1.14
diff -u -p -r1.14 rev.c
--- rev.c   13 Jan 2022 05:10:46 -  1.14
+++ rev.c   27 Jan 2022 14:50:41 -
@@ -40,17 +40,16 @@
 #include 
 #include 
 
+int multibyte;
+
 int isu8cont(unsigned char);
+int rev_file(const char *);
 void usage(void);
 
 int
 main(int argc, char *argv[])
 {
-   char *filename, *p = NULL, *t, *te, *u;
-   FILE *fp;
-   ssize_t len;
-   size_t ps = 0;
-   int ch, multibyte, rval;
+   int ch, rval;
 
setlocale(LC_CTYPE, "");
multibyte = MB_CUR_MAX > 1;
@@ -67,40 +66,13 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
 
-   fp = stdin;
-   filename = "stdin";
rval = 0;
-   do {
-   if (*argv) {
-   if ((fp = fopen(*argv, "r")) == NULL) {
-   warn("%s", *argv);
-   rval = 1;
-   ++argv;
-   continue;
-   }
-   filename = *argv++;
-   }
-   while ((len = getline(, , fp)) != -1) {
-   if (p[len - 1] == '\n')
-   --len;
-   for (t = p + len - 1; t >= p; --t) {
-   te = t;
-   if (multibyte)
-   while (t > p && isu8cont(*t))
-   --t;
-   for (u = t; u <= te; ++u)
-   if (putchar(*u) == EOF)
-   err(1, "stdout");
-   }
-   if (putchar('\n') == EOF)
-   err(1, "stdout");
-   }
-   if (ferror(fp)) {
-   warn("%s", filename);
-   rval = 1;
-   }
-   (void)fclose(fp);
-   } while(*argv);
+   if (argc == 0) {
+   rval = rev_file(NULL);
+   } else {
+   for (; *argv != NULL; argv++)
+   rval |= rev_file(*argv);
+   }
return rval;
 }
 
@@ -108,6 +80,54 @@ int
 isu8cont(unsigned char c)
 {
return (c & (0x80 | 0x40)) == 0x80;
+}
+
+int
+rev_file(const char *path)
+{
+   char *p = NULL, *t, *te, *u;
+   const char *filename;
+   FILE *fp;
+   size_t ps = 0;
+   ssize_t len;
+   int rval = 0;
+
+   if (path != NULL) {
+   fp = fopen(path, "r");
+   if (fp == NULL) {
+   warn("%s", path);
+   return 1;
+   }
+   filename = path;
+   } else {
+   fp = stdin;
+   filename = "stdin";
+   }
+
+   while ((len = getline(, , fp)) != -1) {
+   if (p[len - 1] == '\n')
+   --len;
+   for (t = p + len - 1; t >= p; --t) {
+   te = t;
+   if (multibyte)
+   while (t > p && isu8cont(*t))
+   --t;
+   for (u = t; u <= te; ++u)
+   if (putchar(*u) == EOF)
+   err(1, "stdout");
+   }
+   if (putchar('\n') == EOF)
+   err(1, "stdout");
+   }
+   free(p);
+   if (ferror(fp)) {
+   warn("%s", filename);
+   rval = 1;
+   }
+
+   (void)fclose(fp);
+
+   return rval;
 }
 
 void



Re: unlock mmap(2) for anonymous mappings

2022-01-27 Thread Klemens Nanni
On Tue, Jan 25, 2022 at 07:54:52AM +, Klemens Nanni wrote:
> > Could we use a vm_map_assert_locked() or something similar that reflect
> > the exclusive or shared (read) lock comments?  I don't trust comments.
> > It's too easy to miss a lock in a code path.
> 
> This survives desktop usage, running regress and building kernels on
> amd64.
> 
> I'll throw it at sparc64 soon.
> 
> > 
> > > So annotate functions using `size' wrt. the required lock.

Here's a better diff that asserts for read, write or any type of vm_map
lock.

vm_map_lock() and vm_map_lock_read() are used for exclusive and shared
access respectively;  unless I missed something, no code path is purely
protected by vm_map_lock_read() alone, i.e. functions called with a read
lock held by the callee are also called with a write lock elsewhere.

That means my new vm_map_assert_locked_read() is currently unused, but
vm_map_assert_locked_any() and vm_map_assert_locked_write() are now used
to validate existing function comments as well as a few new places.

amd64 and sparc64 are happy with this, both daily drivers as well as
build/regress machines.

I'd appreciate more tests and reports about running with this diff and
mmap(2) unlocked.

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   27 Jan 2022 10:45:47 -
@@ -805,6 +805,8 @@ uvm_map_sel_limits(vaddr_t *min, vaddr_t
  * Fills in *start_ptr and *end_ptr to be the first and last entry describing
  * the space.
  * If called with prefilled *start_ptr and *end_ptr, they are to be correct.
+ *
+ * map must be at least read-locked.
  */
 int
 uvm_map_isavail(struct vm_map *map, struct uvm_addr_state *uaddr,
@@ -815,6 +817,8 @@ uvm_map_isavail(struct vm_map *map, stru
struct uvm_map_addr *atree;
struct vm_map_entry *i, *i_end;
 
+   vm_map_assert_locked_any(map);
+
if (addr + sz < addr)
return 0;
 
@@ -1821,6 +1825,8 @@ boolean_t
 uvm_map_lookup_entry(struct vm_map *map, vaddr_t address,
 struct vm_map_entry **entry)
 {
+   vm_map_assert_locked_any(map);
+
*entry = uvm_map_entrybyaddr(>addr, address);
return *entry != NULL && !UVM_ET_ISHOLE(*entry) &&
(*entry)->start <= address && (*entry)->end > address;
@@ -2206,6 +2212,8 @@ uvm_unmap_kill_entry(struct vm_map *map,
  * If remove_holes, then remove ET_HOLE entries as well.
  * If markfree, entry will be properly marked free, otherwise, no replacement
  * entry will be put in the tree (corrupting the tree).
+ *
+ * map must be locked.
  */
 void
 uvm_unmap_remove(struct vm_map *map, vaddr_t start, vaddr_t end,
@@ -2214,6 +,8 @@ uvm_unmap_remove(struct vm_map *map, vad
 {
struct vm_map_entry *prev_hint, *next, *entry;
 
+   vm_map_assert_locked_write(map);
+
start = MAX(start, map->min_offset);
end = MIN(end, map->max_offset);
if (start >= end)
@@ -2976,12 +2986,17 @@ uvm_tree_sanity(struct vm_map *map, char
UVM_ASSERT(map, addr == vm_map_max(map), file, line);
 }
 
+/*
+ * map must be at least read-locked.
+ */
 void
 uvm_tree_size_chk(struct vm_map *map, char *file, int line)
 {
struct vm_map_entry *iter;
vsize_t size;
 
+   vm_map_assert_locked_any(map);
+
size = 0;
RBT_FOREACH(iter, uvm_map_addr, >addr) {
if (!UVM_ET_ISHOLE(iter))
@@ -4268,7 +4283,7 @@ uvm_map_submap(struct vm_map *map, vaddr
  * uvm_map_checkprot: check protection in map
  *
  * => must allow specific protection in a fully allocated region.
- * => map mut be read or write locked by caller.
+ * => map must be read or write locked by caller.
  */
 boolean_t
 uvm_map_checkprot(struct vm_map *map, vaddr_t start, vaddr_t end,
@@ -4276,6 +4291,8 @@ uvm_map_checkprot(struct vm_map *map, va
 {
struct vm_map_entry *entry;
 
+   vm_map_assert_locked_any(map);
+
if (start < map->min_offset || end > map->max_offset || start > end)
return FALSE;
if (start == end)
@@ -5557,6 +5577,46 @@ vm_map_unbusy_ln(struct vm_map *map, cha
mtx_leave(>flags_lock);
if (oflags & VM_MAP_WANTLOCK)
wakeup(>flags);
+}
+
+void
+vm_map_assert_locked_any_ln(struct vm_map *map, char *file, int line)
+{
+   LPRINTF(("map assert read or write locked: %p (at %s %d)\n", map, file, 
line));
+   if ((map->flags & VM_MAP_INTRSAFE) == 0)
+   rw_assert_anylock(>lock);
+   else
+   MUTEX_ASSERT_LOCKED(>mtx);
+}
+
+void
+vm_map_assert_locked_read_ln(struct vm_map *map, char *file, int line)
+{
+   LPRINTF(("map assert read locked: %p (at %s %d)\n", map, file, line));
+   if ((map->flags & VM_MAP_INTRSAFE) == 0)
+   rw_assert_rdlock(>lock);
+   else
+   MUTEX_ASSERT_LOCKED(>mtx);
+}
+
+void

Re: rpki-client RFC "compliant" MFT parsing

2022-01-27 Thread Claudio Jeker
On Thu, Jan 27, 2022 at 07:46:32AM +0100, Theo Buehler wrote:
> On Wed, Jan 26, 2022 at 04:42:04PM +0100, Claudio Jeker wrote:
> > So the RFC is not very clear but in general the idea is that if multiple
> > MFTs are available the newest one (highest manifest number) should be
> > used.
> > 
> > In our case there are two possible MFTs available the previously valid on
> > and the now downloaded one. So adjust the parser code so that both files
> > are opened and parsed and the x509 is verified. Checks like the
> > thisUpdate/nextUpdate validity and FileAndHash sequence are postponed.
> > Compare these two mfts and decide which one should be used.
> > Now check everything that was postponed.
> > 
> > When checking the hash of files in the MFT check both locations and
> > remember which file was the actual match. It is important that later on
> > the same file is opened.
> > 
> > The error checking around MFTs had to be adjusted in some places since it
> > turned out to be too noisy on stale caches.
> > 
> > Please test and report unexpected behaviour.
> 
> This seems to work fine here. I have read the diff and it looks good,
> but have not reviewed it thoroughly. Do you consider it ready for that?

I have parts I'm not super happy with but have no better idea yet.
Mainly the changes to parse_entity() make that function even more complex
and error prone. proc_parser_mft_check() is the other function where I'm
not sure. So happy for any feedback to improve those bits.
 
> One thing that stood out in mft_compare():
> 
> > +int
> > +mft_compare(const struct mft *a, const struct mft *b)
> > +{
> > +   BIGNUM *abn = NULL, *bbn = NULL;
> > +   int r;
> > +
> > +   if (b == NULL)
> > +   return 1;
> > +   if (a == NULL)
> > +   return 0;
> > +
> > +   BN_hex2bn(, a->seqnum);
> > +   BN_hex2bn(, b->seqnum);
> 
> These need error checking.
> 
> Is it necessary to convert these back into BIGNUMs? Can't we compare
> first the string length and if it's equal do a strcmp?

I think it is possible but I was not sure if it is always correct so I
bailed on that plan and used BN_cmp().
I have to look at how OpenSSL does the BN_bn2hex() conversion. I noticed
that the numbers seen are mostly 2 or 4 bytes long with leding 0.

I agree that this comparision should be easier. Another option would be to
not convert seqnum and keep it as BIGNUM but I'm not a fan of that.
Especially inside struct mft.
 
> > +   r = BN_cmp(abn, bbn);
> > +   BN_free(abn);
> > +   BN_free(bbn);
> > +
> > +   if (r < 0)
> > +   return 0;
> > +
> > +   /*
> > +* Equal sequence numbers should not happen for different content.
> > +* In this case we prefer the newer MFT.
> > +*/
> > +   return 1;
> >  }
> 

-- 
:wq Claudio