Re: Why store pointers for some functions in malloc.c?

2023-10-17 Thread Masato Asou
From: Otto Moerbeek 
Date: Wed, 18 Oct 2023 07:28:47 +0200

> On Wed, Oct 18, 2023 at 09:23:49AM +0900, Masato Asou wrote:
> 
>> Hello tech@ and otto,
>> 
>> Why do only some calling functions store the pinttes in region_info as
>> below:
>> 
>> static void *
>> malloc_bytes(struct dir_info *d, size_t size, void *f)
>> {
>> 
>> found:
>> if (i == 0 && k == 0 && DO_STATS) {
>> struct region_info *r = find(d, bp->page);
>> STATS_SETF(r, f);
>> }
>> 
>> I found following mail from otto:
>> https://marc.info/?l=openbsd-tech=168171382927798=2
>> > The null "f" values (call sites) are due to the sampling nature of
>> > small allocations. Recording all call sites of all potential leaks
>> > introduces too much overhead.
>> 
>> Is this the answer to my question?
>> --
>> ASOU Masato
> 
> Yes.
>  
> The reason is that (in the existing code) there's only one pointer per
> region_info available to store callers. So for a chunk page (which has
> many small alocations) ony slot 0 gets recorded.

OK.

> But there's a diff I posted last week on tech@ that will change this
> so that all call sites are recorded (in a different location and only
> if D is used). It will also report more details when a write of a free
> chunk is detected.  That diff could use some review/testing.

I'll checkt the your posted diff.

Thank your for your information!
--
ASOU Masato



Re: Why store pointers for some functions in malloc.c?

2023-10-17 Thread Otto Moerbeek
On Wed, Oct 18, 2023 at 09:23:49AM +0900, Masato Asou wrote:

> Hello tech@ and otto,
> 
> Why do only some calling functions store the pinttes in region_info as
> below:
> 
> static void *
> malloc_bytes(struct dir_info *d, size_t size, void *f)
> {
> 
> found:
> if (i == 0 && k == 0 && DO_STATS) {
> struct region_info *r = find(d, bp->page);
> STATS_SETF(r, f);
> }
> 
> I found following mail from otto:
> https://marc.info/?l=openbsd-tech=168171382927798=2
> > The null "f" values (call sites) are due to the sampling nature of
> > small allocations. Recording all call sites of all potential leaks
> > introduces too much overhead.
> 
> Is this the answer to my question?
> --
> ASOU Masato

Yes.
 
The reason is that (in the existing code) there's only one pointer per
region_info available to store callers. So for a chunk page (which has
many small alocations) ony slot 0 gets recorded.

But there's a diff I posted last week on tech@ that will change this
so that all call sites are recorded (in a different location and only
if D is used). It will also report more details when a write of a free
chunk is detected.  That diff could use some review/testing.
 
-Otto



Re: pkg_add: No progress meter: failed termcap loop

2023-10-17 Thread Andrew Hewus Fresh
On Tue, Oct 17, 2023 at 06:34:58PM -0700, Andrew Hewus Fresh wrote:
> On Tue, Oct 17, 2023 at 06:13:30PM -0700, Andrew Hewus Fresh wrote:
> > On Tue, Oct 17, 2023 at 05:10:44PM -0700, Greg Steuck wrote:
> > > I just got myself a fresh snapshot with libncurses.so.15.0:
> > > OpenBSD 7.4-current (GENERIC.MP) #1409: Tue Oct 17 17:08:49 MDT 2023
> > > 
> > > I get some unhappiness now:
> > > # pkg_add -ui
> > > No progress meter: failed termcap loop
> > > quirks-6.161 signed on 2023-10-16T11:16:03Z
> > > 
> > > Fallout from the ncurses upgrade?


 
 And this is committed with an upstream PR created.

 https://github.com/jonathanstowe/Term-Cap/pull/17
 
> Index: gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm
> ===
> RCS file: /cvs/src/gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm,v
> retrieving revision 1.2
> diff -u -p -r1.2 Cap.pm
> --- gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm 5 Feb 2017 00:32:03 -   
> 1.2
> +++ gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm 18 Oct 2023 01:25:11 -
> @@ -280,7 +280,7 @@ sub Tgetent
>  
>  $first = 0;# first entry (keeps term name)
>  
> -$max = 32; # max :tc=...:'s
> +$max = 64; # max :tc=...:'s
>  
>  if ($entry)
>  {
> 



Re: pkg_add: No progress meter: failed termcap loop

2023-10-17 Thread Andrew Hewus Fresh
On Tue, Oct 17, 2023 at 06:34:58PM -0700, Andrew Hewus Fresh wrote:
> On Tue, Oct 17, 2023 at 06:13:30PM -0700, Andrew Hewus Fresh wrote:
> > On Tue, Oct 17, 2023 at 05:10:44PM -0700, Greg Steuck wrote:
> > > I just got myself a fresh snapshot with libncurses.so.15.0:
> > > OpenBSD 7.4-current (GENERIC.MP) #1409: Tue Oct 17 17:08:49 MDT 2023
> > > 
> > > I get some unhappiness now:
> > > # pkg_add -ui
> > > No progress meter: failed termcap loop
> > > quirks-6.161 signed on 2023-10-16T11:16:03Z
> > > 
> > > Fallout from the ncurses upgrade?
> > 
> > Seems likely.  I can reproduce with this code that's similar to
> > what OpenBSD::ProgressMeter::Term does:
> > 
> > $ perl -MPOSIX -MTerm::Cap -e 'Term::Cap->Tgetent({ OSPEED => 
> > POSIX::Termios->new->getospeed })' 
> > failed termcap loop at att610+cvis at -e line 1.
> > 
> > or even just:
> > 
> > $ perl -MTerm::Cap -e 'Term::Cap->Tgetent'  
> >  
> > failed termcap loop at att610+cvis at -e line 1.
> > 
> > Wow though, the only hits google has for that "failed termcap loop" is
> > the file it is in so incredibly impressive.
> 
> It appears 20 years ago nobody expected this complicated an
> /etc/termcap.  This patch seems to fix the glitch.  
> 
> It has been 32 since at least it was moved back from SVN to CVS in 2004
> which is when git history stops.
> https://github.com/jonathanstowe/Term-Cap/blob/3a1193a8c5457d0ca77ea43d1be73712303a359c/Cap.pm#L254

Looking a bit harder, before that upstream for Term::Cap was perl core.

So that 32 limit dates back to 1995 and perl 5.001, I guess thinking 28
years into the future was enough.

https://github.com/Perl/perl5/commit/748a93069b3d16374a9859d1456065dd3ae11394#diff-0961d7f68bf68cb479f1fbd33f77f275bab83bfab124c64ab82b20ec5e9d6d87R77

 
> (I only needed to change this to 36, but how future proof is that?)
> 
> Comments, OK?
> 
> 
> Index: gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm
> ===
> RCS file: /cvs/src/gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm,v
> retrieving revision 1.2
> diff -u -p -r1.2 Cap.pm
> --- gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm 5 Feb 2017 00:32:03 -   
> 1.2
> +++ gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm 18 Oct 2023 01:25:11 -
> @@ -280,7 +280,7 @@ sub Tgetent
>  
>  $first = 0;# first entry (keeps term name)
>  
> -$max = 32; # max :tc=...:'s
> +$max = 64; # max :tc=...:'s
>  
>  if ($entry)
>  {
> 

-- 
andrew

Hey, I think I see a barn up ahead.
  -- The American Astronaut



mention U-Boot file and offset for Rockchip RK356x

2023-10-17 Thread Kevin Lo
ok?

Index: distrib/notes/arm64/prep
===
RCS file: /cvs/src/distrib/notes/arm64/prep,v
retrieving revision 1.18
diff -u -p -u -p -r1.18 prep
--- distrib/notes/arm64/prep10 Apr 2023 12:57:15 -  1.18
+++ distrib/notes/arm64/prep18 Oct 2023 01:29:11 -
@@ -132,3 +132,8 @@ Install on systems without a supported m
of=/dev/sdXc seek=64
dd if=/usr/local/share/u-boot/board/u-boot.itb \
of=/dev/sdXc seek=16384
+
+  For systems based on Rockchip RK356x SoCs:
+
+   dd if=/usr/local/share/u-boot/board/u-boot-rockchip.bin \
+   of=/dev/sdXc seek=64



Re: pkg_add: No progress meter: failed termcap loop

2023-10-17 Thread Andrew Hewus Fresh
On Tue, Oct 17, 2023 at 06:13:30PM -0700, Andrew Hewus Fresh wrote:
> On Tue, Oct 17, 2023 at 05:10:44PM -0700, Greg Steuck wrote:
> > I just got myself a fresh snapshot with libncurses.so.15.0:
> > OpenBSD 7.4-current (GENERIC.MP) #1409: Tue Oct 17 17:08:49 MDT 2023
> > 
> > I get some unhappiness now:
> > # pkg_add -ui
> > No progress meter: failed termcap loop
> > quirks-6.161 signed on 2023-10-16T11:16:03Z
> > 
> > Fallout from the ncurses upgrade?
> 
> Seems likely.  I can reproduce with this code that's similar to
> what OpenBSD::ProgressMeter::Term does:
> 
> $ perl -MPOSIX -MTerm::Cap -e 'Term::Cap->Tgetent({ OSPEED => 
> POSIX::Termios->new->getospeed })' 
> failed termcap loop at att610+cvis at -e line 1.
> 
> or even just:
> 
> $ perl -MTerm::Cap -e 'Term::Cap->Tgetent'
>
> failed termcap loop at att610+cvis at -e line 1.
> 
> Wow though, the only hits google has for that "failed termcap loop" is
> the file it is in so incredibly impressive.

It appears 20 years ago nobody expected this complicated an
/etc/termcap.  This patch seems to fix the glitch.  

It has been 32 since at least it was moved back from SVN to CVS in 2004
which is when git history stops.
https://github.com/jonathanstowe/Term-Cap/blob/3a1193a8c5457d0ca77ea43d1be73712303a359c/Cap.pm#L254

(I only needed to change this to 36, but how future proof is that?)

Comments, OK?


Index: gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm
===
RCS file: /cvs/src/gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm,v
retrieving revision 1.2
diff -u -p -r1.2 Cap.pm
--- gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm   5 Feb 2017 00:32:03 -   
1.2
+++ gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm   18 Oct 2023 01:25:11 -
@@ -280,7 +280,7 @@ sub Tgetent
 
 $first = 0;# first entry (keeps term name)
 
-$max = 32; # max :tc=...:'s
+$max = 64; # max :tc=...:'s
 
 if ($entry)
 {



Re: pkg_add: No progress meter: failed termcap loop

2023-10-17 Thread Andrew Hewus Fresh
On Tue, Oct 17, 2023 at 05:10:44PM -0700, Greg Steuck wrote:
> I just got myself a fresh snapshot with libncurses.so.15.0:
> OpenBSD 7.4-current (GENERIC.MP) #1409: Tue Oct 17 17:08:49 MDT 2023
> 
> I get some unhappiness now:
> # pkg_add -ui
> No progress meter: failed termcap loop
> quirks-6.161 signed on 2023-10-16T11:16:03Z
> 
> Fallout from the ncurses upgrade?

Seems likely.  I can reproduce with this code that's similar to
what OpenBSD::ProgressMeter::Term does:

$ perl -MPOSIX -MTerm::Cap -e 'Term::Cap->Tgetent({ OSPEED => 
POSIX::Termios->new->getospeed })' 
failed termcap loop at att610+cvis at -e line 1.

or even just:

$ perl -MTerm::Cap -e 'Term::Cap->Tgetent'  
 
failed termcap loop at att610+cvis at -e line 1.

Wow though, the only hits google has for that "failed termcap loop" is
the file it is in so incredibly impressive.

l8rZ,
-- 
andrew

The programmer's national anthem is 'GH!!'.



Why store pointers for some functions in malloc.c?

2023-10-17 Thread Masato Asou
Hello tech@ and otto,

Why do only some calling functions store the pinttes in region_info as
below:

static void *
malloc_bytes(struct dir_info *d, size_t size, void *f)
{

found:
if (i == 0 && k == 0 && DO_STATS) {
struct region_info *r = find(d, bp->page);
STATS_SETF(r, f);
}

I found following mail from otto:
https://marc.info/?l=openbsd-tech=168171382927798=2
> The null "f" values (call sites) are due to the sampling nature of
> small allocations. Recording all call sites of all potential leaks
> introduces too much overhead.

Is this the answer to my question?
--
ASOU Masato



Re: HAMMER2 filesystem for OpenBSD

2023-10-17 Thread Greg Steuck
Chris Narkiewicz  writes:

> On Tue, 2023-10-17 at 16:22 -0600, Theo de Raadt wrote:
>> What will come of this discussion of opinions?
>
> If it's doable and the code quality is acceptable, I see 2 outcomes:
> 1. I could start looking for sponsorship, as I feel like my level of
> expertise is too limited to chew it myself
> 2. perhaps with a right guidance I could try to bite it myself (not so
> sure about it, but keen on finding out).
>
> I'm trying to contact the author atm to discuss his position and his
> plans regarding the code so see if there is any alignment.
>
> Week ago, he added a disclaimer in the readme that he plans shift his
> focus when FreeBSD write support is stabilized. If there is a limited
> window of opportunity, I thought it's worth looking at it while there
> is active interest.
>
> TBH, I don't know what would it take. The patch looks minimal, but I
> suspect it's just tip of the iceberg and I lack the knowledge to
> estimate how big the underwater part is. Especially the cost of
> maintenance. Therefore, I decided to reach out to tech, kindly asking
> about devs opinion or technical expertise on that matter.

Pointing to a repository with a diff against an old tree is minimally
interesting. If you report that you tested it and detail the outcome,
the level of interest may rise to the point that somebody else might
try. You can substantially increase the chances by forward-porting the
change to -current and testing it.

Thanks
Greg



pkg_add: No progress meter: failed termcap loop

2023-10-17 Thread Greg Steuck
I just got myself a fresh snapshot with libncurses.so.15.0:
OpenBSD 7.4-current (GENERIC.MP) #1409: Tue Oct 17 17:08:49 MDT 2023

I get some unhappiness now:
# pkg_add -ui
No progress meter: failed termcap loop
quirks-6.161 signed on 2023-10-16T11:16:03Z

Fallout from the ncurses upgrade?

Thanks
Greg



syslogd udp dropped counter

2023-10-17 Thread Alexander Bluhm
Hi,

Now that syslogd handles delayed DNS lookups, I think we should
count dropped packets to UDP loghosts.  Although not every dropped
UDP packet can be detected, the message makes the admin aware that
there may be a blind spot during startup.

syslogd[26493]: dropped 8 messages to udp loghost "@udp://loghost"

Debug and log messages were improved, especially if UDP looging is
shut down permanently.  Also do not print 'last message repeated'
if the message was dropped.

ok?

bluhm

Index: usr.sbin/syslogd/syslogd.c
===
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.278
diff -u -p -r1.278 syslogd.c
--- usr.sbin/syslogd/syslogd.c  12 Oct 2023 22:36:54 -  1.278
+++ usr.sbin/syslogd/syslogd.c  17 Oct 2023 23:30:05 -
@@ -241,6 +241,7 @@ int NoVerify = 0;   /* do not verify TLS 
 const char *ClientCertfile = NULL;
 const char *ClientKeyfile = NULL;
 const char *ServerCAfile = NULL;
+intudpsend_dropped = 0;/* messages dropped due to UDP not ready */
 inttcpbuf_dropped = 0; /* count messages dropped from TCP or TLS */
 intfile_dropped = 0;   /* messages dropped due to file system full */
 intinit_dropped = 0;   /* messages dropped during initialization */
@@ -1820,6 +1821,7 @@ logmsg(struct msg *msg, int flags, char 
(f->f_type != F_PIPE && f->f_type != F_FORWUDP &&
f->f_type != F_FORWTCP && f->f_type != F_FORWTLS))) &&
(flags & MARK) == 0 && msglen == f->f_prevlen &&
+   f->f_dropped == 0 &&
!strcmp(msg->m_msg, f->f_prevline) &&
!strcmp(from, f->f_prevhost)) {
strlcpy(f->f_lasttime, msg->m_timestamp,
@@ -2005,14 +2007,14 @@ fprintlog(struct filed *f, int flags, ch
 
switch (f->f_type) {
case F_UNUSED:
-   log_debug("%s", "");
+   log_debug("");
break;
 
case F_FORWUDP:
-   log_debug(" %s", f->f_un.f_forw.f_loghost);
+   log_debugadd(" %s", f->f_un.f_forw.f_loghost);
if (f->f_un.f_forw.f_addr.ss_family == AF_UNSPEC) {
-   log_warnx("not resolved \"%s\"",
-   f->f_un.f_forw.f_loghost);
+   log_debug(" (dropped not resolved)");
+   f->f_dropped++;
break;
}
l = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len +
@@ -2040,14 +2042,30 @@ fprintlog(struct filed *f, int flags, ch
case ENETUNREACH:
case ENOBUFS:
case EWOULDBLOCK:
+   log_debug(" (dropped send error)");
+   f->f_dropped++;
/* silently dropped */
break;
default:
+   log_debug(" (dropped permanent send error)");
+   f->f_dropped++;
f->f_type = F_UNUSED;
-   log_warn("sendmsg to \"%s\"",
+   snprintf(ebuf, sizeof(ebuf),
+   "to udp loghost \"%s\"",
+   f->f_un.f_forw.f_loghost);
+   dropped_warn(>f_dropped, ebuf);
+   log_warn("loghost \"%s\" disabled, sendmsg",
f->f_un.f_forw.f_loghost);
break;
}
+   } else {
+   log_debug("");
+   if (f->f_dropped > 0) {
+   snprintf(ebuf, sizeof(ebuf),
+   "to udp loghost \"%s\"",
+   f->f_un.f_forw.f_loghost);
+   dropped_warn(>f_dropped, ebuf);
+   }
}
break;
 
@@ -2056,7 +2074,7 @@ fprintlog(struct filed *f, int flags, ch
log_debugadd(" %s", f->f_un.f_forw.f_loghost);
if (EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->output) >=
MAX_TCPBUF) {
-   log_debug(" (dropped)");
+   log_debug(" (dropped tcpbuf full)");
f->f_dropped++;
break;
}
@@ -2077,12 +2095,12 @@ fprintlog(struct filed *f, int flags, ch
(char *)iov[3].iov_base, (char *)iov[4].iov_base,
(char *)iov[5].iov_base, (char *)iov[6].iov_base);
if (l < 0) {
-   log_debug(" (dropped evbuffer_add_printf)");
+   log_debug(" (dropped evbuffer add)");
f->f_dropped++;

Re: HAMMER2 filesystem for OpenBSD

2023-10-17 Thread Chris Narkiewicz
On Tue, 2023-10-17 at 16:22 -0600, Theo de Raadt wrote:
> What will come of this discussion of opinions?

If it's doable and the code quality is acceptable, I see 2 outcomes:
1. I could start looking for sponsorship, as I feel like my level of
expertise is too limited to chew it myself
2. perhaps with a right guidance I could try to bite it myself (not so
sure about it, but keen on finding out).

I'm trying to contact the author atm to discuss his position and his
plans regarding the code so see if there is any alignment.

Week ago, he added a disclaimer in the readme that he plans shift his
focus when FreeBSD write support is stabilized. If there is a limited
window of opportunity, I thought it's worth looking at it while there
is active interest.

TBH, I don't know what would it take. The patch looks minimal, but I
suspect it's just tip of the iceberg and I lack the knowledge to
estimate how big the underwater part is. Especially the cost of
maintenance. Therefore, I decided to reach out to tech, kindly asking
about devs opinion or technical expertise on that matter.

If such effort is not aligned with OpenBSD plans, I'll stop here.

Cheers,
Chris



Re: HAMMER2 filesystem for OpenBSD

2023-10-17 Thread Theo de Raadt
What will come of this discussion of opinions?

Chris Narkiewicz  wrote:

> Hi,
> 
> Tomohiro Kusumi is currently working on HAMMER2 implementation
> for OpenBSD, FreeBSD and NetBSD.
> 
> The repository is here:
> https://github.com/kusumi/openbsd_hammer2
> 
> 
> He maintains repositories for NetBSD, FreeBSD and OpenBSD, which
> suggests that the implementation is portable. He also
> provides a patch for OpenBSD 7.3:
> 
> https://github.com/kusumi/openbsd_hammer2/blob/master/patch/openbsd73.patch
> 
> The patch looks very minimal to me, with no deeper changes to the
> kernel.
> 
> I haven't found any discussion about HAMMER2 in list archives, so I'd
> like to bring it to devs attention, kindly asking for your opinion.
> Does it look like it's worth bringing in? Does it require more work?
> 
> I'd appreciate any opinions from more knowledgable crowd.
> 
> Cheers,
> Chris
> 



HAMMER2 filesystem for OpenBSD

2023-10-17 Thread Chris Narkiewicz
Hi,

Tomohiro Kusumi is currently working on HAMMER2 implementation
for OpenBSD, FreeBSD and NetBSD.

The repository is here:
https://github.com/kusumi/openbsd_hammer2


He maintains repositories for NetBSD, FreeBSD and OpenBSD, which
suggests that the implementation is portable. He also
provides a patch for OpenBSD 7.3:

https://github.com/kusumi/openbsd_hammer2/blob/master/patch/openbsd73.patch

The patch looks very minimal to me, with no deeper changes to the
kernel.

I haven't found any discussion about HAMMER2 in list archives, so I'd
like to bring it to devs attention, kindly asking for your opinion.
Does it look like it's worth bringing in? Does it require more work?

I'd appreciate any opinions from more knowledgable crowd.

Cheers,
Chris



Re: smtpd: implement nullmx RFC 7505

2023-10-17 Thread Philipp
[2023-10-17 17:32] Omar Polo 
> sorry for the terrifc delay.
>
> On 2023/10/01 14:59:15 +0200, Philipp  wrote:
> > Hi
> > 
> > Setting Null MX is a way for domainowners to indicate that the domain
> > does not accept mail. Currently a Null MX causes a tempfail and the
> > mail will be queued and tried to resubmitted till a timeout. With the
> > attached patch a Null MX causes a permfail. This way the sender will
> > directly get a bounce with the message "Domain does not accept mail".
>
> I'm not sure how much widespread the usage is, but it doesn't seem a
> bad feature.  It's simple to implement and it provides some (very
> small) value.

There is a blogpost[0] which says about 1% of the domains use Null MX and
about 0.7% set the MX to "localhost." (probably for the same propose).

> In general I'm OK with the idea, but would need some OKs from other
> developers too.
>
> There is one part of the RFC7505 that I'd like to quote and discuss
> with you however.  The last paragraph of the section 3 says:
>
> : A domain that advertises a null MX MUST NOT advertise any other MX
> : RR.
>
> Your implementation handles the case where there are more than one MX
> by setting the `nullmx' field in the shared struct when we encounter
> one, and then don't process the other MXs when that field is set.
> This is fine.
>
> However, I think we can simplify here by not honouring the Null MX
> when there are other MX records.  We're not violating the RFC.  See
> diff below to see what I mean.  The only difference is in dns.c, the
> rest is the same with yours.

My reasaning for that was: When you set Null MX you explicitly opt out
from reciving mail even when you violate the spec. But if you want
it diffrent I can change it.

But I don't think your proposed patch is a good solution, because the
result depend on the order of the RR in the repsonse. The problem is
when the first entry in the response is a Null MX your patch truncate
the other results and a bounce is generated. But when the Null MX is
later in the response the other entries are used to deliver the mail.

> So far I've only compile-tested the code.  I don't have a spare domain
> to test and don't know of anyone using a Null MX.

To test Null MX you can use example.com. To test the localhost patch a
friend of me has set up mxtest.yannikenss.de.

> > Because some domains set the MX record to "localhost." to get a similar
> > efect the secound patch ignores "localhost." MX entries and handles a MX
> > containing only "localhost." records like a Null MX.
>
> This could be simplified too.  On top of diff below, it would need
> just something among the lines of:

When localhost and Null MX should be handled the same this could be
simplified in one check, yes. But that "localhost." and Null MX are
handled different was on purpose. Because I would say setting a Null MX
is a explicit opt out from reciving mail and setting MX to localhost
is implicit. As said before, I have no problem which changing this.

> I'm still not convinced about this part however.  It feels wrong to me
> to hardcode such a check, it seems too much paranoic.  The follow-up
> would be to check for localhost in dns_dispatch_host too?  ;)

The idea[1] about this part was because setting "localhost." as MX is used
in a similiar way as Null MX[0]. So handle this in a simmilar way as
Null MX make sense. This way the sender will get a better bounce message.

Philipp

[0] https://www.netmeister.org/blog/mx-diversity.html

[1] I still belive OpenSMTPD should only connect to public routable
addresses for relay. So don't connect to something like 127.0.0.1/8,
::1/128, RFC1918 addresses, ULA, ...
But this is independent of this patch.



Re: snmpd [3/16]: Distinguish between parseerror and openfailed for agentx-open-pdu

2023-10-17 Thread Theo Buehler
On Tue, Oct 17, 2023 at 02:51:03PM +0200, Martijn van Duren wrote:
> RFC2741 section 7.1.1 tells us that if a pdu can't be parsed we must
> return a parseerror. Section 7.1 gives an example of "An unrecognized
> value is encountered". The spec is vague is a bit vague on what
> constitutes a parseerror, vs a protocol error, so I don't want to
> muddle too much with that part, but let's at least return an
> appropriate error when a client sends invalid data in the open request.
> 
> The spec clearly states that any error, which is not a parseerror must
> be a openfailed error. So no processingerrors.
> 
> OK?

ok tb



Re: snmpd [1.1/16]: Don't overflow oid in agentx parser

2023-10-17 Thread Theo Buehler
On Tue, Oct 17, 2023 at 02:49:05PM +0200, Martijn van Duren wrote:
> > Currently ax.c doesn't check the maximum length of an OID ax_pdutooid.
> > This can lead to a buffer overflow. Even though it must be fixed, I
> > don't think there's a big risk here, since an attacker would need to have
> > access to the agentx socket, which by default is disabled and defaults
> > to root:_agentx when enabled.
> 
> Here's the libagentx counterpart.

ok for both



Re: snmpd [2.2/16]: Don't set NON_DEFAULT_CONTEXT for agentx-response-pdu

2023-10-17 Thread Theo Buehler
On Tue, Oct 17, 2023 at 02:49:57PM +0200, Martijn van Duren wrote:
> > According to RFC2741 section 6.1.1 an agentx-response-pdu shouldn't have
> > the NON_DEFAULT_CONTEXT set. Remove the argument from ax_response().
> 
> Here's the libagentx counterpart.

ok



Re: smtpd: implement nullmx RFC 7505

2023-10-17 Thread Omar Polo
Hello,

sorry for the terrifc delay.

On 2023/10/01 14:59:15 +0200, Philipp  wrote:
> Hi
> 
> Setting Null MX is a way for domainowners to indicate that the domain
> does not accept mail. Currently a Null MX causes a tempfail and the
> mail will be queued and tried to resubmitted till a timeout. With the
> attached patch a Null MX causes a permfail. This way the sender will
> directly get a bounce with the message "Domain does not accept mail".

I'm not sure how much widespread the usage is, but it doesn't seem a
bad feature.  It's simple to implement and it provides some (very
small) value.

In general I'm OK with the idea, but would need some OKs from other
developers too.

There is one part of the RFC7505 that I'd like to quote and discuss
with you however.  The last paragraph of the section 3 says:

: A domain that advertises a null MX MUST NOT advertise any other MX
: RR.

Your implementation handles the case where there are more than one MX
by setting the `nullmx' field in the shared struct when we encounter
one, and then don't process the other MXs when that field is set.
This is fine.

However, I think we can simplify here by not honouring the Null MX
when there are other MX records.  We're not violating the RFC.  See
diff below to see what I mean.  The only difference is in dns.c, the
rest is the same with yours.

So far I've only compile-tested the code.  I don't have a spare domain
to test and don't know of anyone using a Null MX.

> Because some domains set the MX record to "localhost." to get a similar
> efect the secound patch ignores "localhost." MX entries and handles a MX
> containing only "localhost." records like a Null MX.

This could be simplified too.  On top of diff below, it would need
just something among the lines of:

-   if (rr.rr.mx.preference == 0 && !strcmp(buf, "")) {
+   if ((rr.rr.mx.preference == 0 && !strcmp(buf, "")) ||
+   !strcasecmp(buf, "localhost")) {
if (found)
continue;
m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1);

I'm still not convinced about this part however.  It feels wrong to me
to hardcode such a check, it seems too much paranoic.  The follow-up
would be to check for localhost in dns_dispatch_host too?  ;)


Thanks,

Omar Polo


diff 2d025d839f99dc09ee525c11a4ed09a0f3bbe7d0 
8d6138e5b1e0bc112ff2584d8528e6bc95a39b6f
commit - 2d025d839f99dc09ee525c11a4ed09a0f3bbe7d0
commit + 8d6138e5b1e0bc112ff2584d8528e6bc95a39b6f
blob - 4cf5d23d1d14b5400c6f4429dae0a4f6490073d4
blob + effc07d142895fb2b622242efcd5c69da7f3b67c
--- usr.sbin/smtpd/dns.c
+++ usr.sbin/smtpd/dns.c
@@ -259,8 +259,22 @@ dns_dispatch_mx(struct asr_result *ar, void *arg)
unpack_rr(, );
if (rr.rr_type != T_MX)
continue;
+
print_dname(rr.rr.mx.exchange, buf, sizeof(buf));
buf[strlen(buf) - 1] = '\0';
+
+   if (rr.rr.mx.preference == 0 && !strcmp(buf, "")) {
+   if (found)
+   continue;
+   m_create(s->p, IMSG_MTA_DNS_HOST_END, 0, 0, -1);
+   m_add_id(s->p, s->reqid);
+   m_add_int(s->p, DNS_NULLMX);
+   m_close(s->p);
+   free(s);
+   found++;
+   break;
+   }
+
dns_lookup_host(s, buf, rr.rr.mx.preference);
found++;
}
blob - c0d0fc02931b90409441035d2744923af9e42df1
blob + 25e158b68a88c8485428a2476c1c557f8c60404d
--- usr.sbin/smtpd/mta.c
+++ usr.sbin/smtpd/mta.c
@@ -1088,6 +1088,10 @@ mta_on_mx(void *tag, void *arg, void *data)
else
relay->failstr = "No MX found for domain";
break;
+   case DNS_NULLMX:
+   relay->fail = IMSG_MTA_DELIVERY_PERMFAIL;
+   relay->failstr = "Domain does not accept mail";
+   break;
default:
fatalx("bad DNS lookup error code");
break;
blob - 6781286928da45e6159bce81ff2437011ebdef72
blob + 9f4732d1c27f6ef9f62951f0207f209a83038dcf
--- usr.sbin/smtpd/smtpd.h
+++ usr.sbin/smtpd/smtpd.h
@@ -1026,6 +1026,8 @@ enum dns_error {
DNS_EINVAL,
DNS_ENONAME,
DNS_ENOTFOUND,
+   /* rfc 7505 */
+   DNS_NULLMX,
 };
 
 enum lka_resp_status {



Re: Please test: make ipsec(4) timeouts mpsafe

2023-10-17 Thread Hrvoje Popovski
On 17.10.2023. 1:07, Vitaliy Makkoveev wrote:
>> On 13 Oct 2023, at 18:40, Hrvoje Popovski  wrote:
>>
>> On 12.10.2023. 20:10, Vitaliy Makkoveev wrote:
>>> Hi, MP safe process timeouts were landed to the tree, so time to test
>>> them with network stack :) Diff below makes tdb and ids garbage
>>> collector timeout handlers running without kernel lock. Not for commit,
>>> just share this for tests if someone interesting.
>>
>> Hi,
>>
>> with this diff it seems that it's little slower than without it.
>> 165Kpps with diff
>> 200Kpps without diff
>>
> 
> Hi,
> 
> Thanks for testing. I’m interesting on slower results. I suspect
> enabled/disabled POOL_DEBUG effect. The patched and unpatched builds
> were made from the same sources?

Hi,

I'm running same source with and without diff and with
kern.pool_debug=0.
I've tried few times and sometimes I'm getting same results, but mostly
little slower ...
I have 2 same servers directly connected with 10G x540T an one ipsec
tunnel through that 10G interface.
I'm testing like this:
compile kernel from source - test tunnel
apply your diff with same source - test tunnel



Re: bgpd cleanup around mask2prefixlen

2023-10-17 Thread Theo Buehler
On Tue, Oct 17, 2023 at 04:47:36PM +0200, Claudio Jeker wrote:
> Looking at fixing portable I realized that some bits around mask2prefixlen
> can be cleaned up.
> 
> First in session.c the plen != 0xff check is not needed since it never can
> happen.
> 
> 2nd the checks for sin_len and sin6_len == 0 are also impossible. A
> sockaddr can not have length 0. A default route would at least have
> sin_len == 4 but on OpenBSD even that no longer happens.

Yes, this looks like a mistake must have happened earlier. The only
realistic scenario would be an addr that comes freshly out of memset().
But for those nothing changes and the return 0 remains.

> Last check for RTF_HOST first, then for sa_in != NULL. If RTF_HOST is set
> the netmask is irrelevant.

ok tb.



bgpd cleanup around mask2prefixlen

2023-10-17 Thread Claudio Jeker
Looking at fixing portable I realized that some bits around mask2prefixlen
can be cleaned up.

First in session.c the plen != 0xff check is not needed since it never can
happen.

2nd the checks for sin_len and sin6_len == 0 are also impossible. A
sockaddr can not have length 0. A default route would at least have
sin_len == 4 but on OpenBSD even that no longer happens.

Last check for RTF_HOST first, then for sa_in != NULL. If RTF_HOST is set
the netmask is irrelevant.

-- 
:wq Claudio

Index: kroute.c
===
RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
retrieving revision 1.306
diff -u -p -r1.306 kroute.c
--- kroute.c16 Oct 2023 10:25:45 -  1.306
+++ kroute.c17 Oct 2023 13:18:42 -
@@ -2422,8 +2422,6 @@ mask2prefixlen4(struct sockaddr_in *sa_i
 {
in_addr_t ina;
 
-   if (sa_in->sin_len == 0)
-   return (0);
ina = sa_in->sin_addr.s_addr;
if (ina == 0)
return (0);
@@ -2437,8 +2435,6 @@ mask2prefixlen6(struct sockaddr_in6 *sa_
uint8_t *ap, *ep;
u_intl = 0;
 
-   if (sa_in6->sin6_len == 0)
-   return (0);
/*
 * sin6_len is the size of the sockaddr so subtract the offset of
 * the possibly truncated sin6_addr struct.
@@ -3096,20 +3092,20 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt
switch (sa->sa_family) {
case AF_INET:
sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
-   if (sa_in != NULL) {
-   kf->prefixlen = mask2prefixlen4(sa_in);
-   } else if (rtm->rtm_flags & RTF_HOST)
+   if (rtm->rtm_flags & RTF_HOST)
kf->prefixlen = 32;
+   else if (sa_in != NULL)
+   kf->prefixlen = mask2prefixlen4(sa_in);
else
kf->prefixlen =
prefixlen_classful(kf->prefix.v4.s_addr);
break;
case AF_INET6:
sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
-   if (sa_in6 != NULL) {
-   kf->prefixlen = mask2prefixlen6(sa_in6);
-   } else if (rtm->rtm_flags & RTF_HOST)
+   if (rtm->rtm_flags & RTF_HOST)
kf->prefixlen = 128;
+   else if (sa_in6 != NULL)
+   kf->prefixlen = mask2prefixlen6(sa_in6);
else
fatalx("in6 net addr without netmask");
break;
Index: session.c
===
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.449
diff -u -p -r1.449 session.c
--- session.c   16 Oct 2023 10:25:46 -  1.449
+++ session.c   16 Oct 2023 17:14:41 -
@@ -1241,8 +1241,7 @@ get_alternate_addr(struct bgpd_addr *loc
plen = mask2prefixlen(
match->ifa_addr->sa_family,
match->ifa_netmask);
-   if (plen != 0xff &&
-   prefix_compare(local, remote, plen) == 0)
+   if (prefix_compare(local, remote, plen) == 0)
connected = 1;
}
break;



snmpd [16/16]: Keep track of exact registrations via AgentX

2023-10-17 Thread Martijn van Duren
This diff I'm least convinced about, but I do want to put it out there.
As far as I'm aware RFC2741 places no restrictions on direct mapping of
unregistrations on registrations. Meaning that if I register
1.3.6.1.2.[1-10] and I just unregister 1.3.6.1.2.5 this should leave
1.3.6.1.2.[1-4] and 1.3.6.1.2.[6-10] and this is what currently is
implemented (assuming previous (un)register diffs).

However, RFC2742 specifies AgentxRegistrationEntry, which presents
the the data as presented in the agentx-register-pdu. This implies
that an unregister is expected to be an exact counterpart to 
agentx-register-pdu, because else an AgentxRegistrationEntry would
need to be split up, which would be a horror-show.

Do we want to add this restriction and keep the road open to
AGENTX-MIB support? Since range support is currently broken anyway
this won't cause any problems.

Thoughts? OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index 79900d6..60dc4df 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -70,11 +70,28 @@ struct appl_agentx_session {
struct ax_oid sess_oid;
struct ax_ostring sess_descr;
struct appl_backend sess_backend;
+   TAILQ_HEAD(, appl_agentx_registration) sess_registrations;
 
RB_ENTRY(appl_agentx_session) sess_entry;
TAILQ_ENTRY(appl_agentx_session) sess_conn_entry;
 };
 
+/* RFC2742: AGENTX-MIB:AgentxRegistrationEntry */
+struct appl_agentx_registration {
+   uint32_t reg_index;
+   char reg_context[APPL_CONTEXTNAME_MAX + 1];
+   struct ax_oid reg_start;
+   uint8_t reg_rangesubid;
+   uint32_t reg_upperbound;
+   uint8_t reg_priority;
+   uint8_t reg_timeout;
+   uint8_t reg_instance;
+
+   struct appl_agentx_session *reg_session;
+
+   TAILQ_ENTRY(appl_agentx_registration) reg_entry;
+};
+
 void appl_agentx_listen(struct agentx_master *);
 void appl_agentx_accept(int, short, void *);
 void appl_agentx_free(struct appl_agentx_connection *, enum appl_close_reason);
@@ -106,6 +123,7 @@ struct appl_backend_functions appl_agentx_functions = {
.ab_getnext = appl_agentx_getnext,
.ab_getbulk = NULL, /* not properly supported in application.c and 
libagentx */
 };
+static uint32_t appl_agentx_reg_index = 1;
 
 RB_HEAD(appl_agentx_conns, appl_agentx_connection) appl_agentx_conns =
 RB_INITIALIZER(_agentx_conns);
@@ -477,6 +495,7 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
goto fail;
}
session->sess_descr.aos_string = NULL;
+   TAILQ_INIT(&(session->sess_registrations));
 
session->sess_conn = conn;
if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
@@ -624,6 +643,12 @@ void
 appl_agentx_session_free(struct appl_agentx_session *session)
 {
struct appl_agentx_connection *conn = session->sess_conn;
+   struct appl_agentx_registration *reg;
+
+   while ((reg = TAILQ_FIRST(&(session->sess_registrations))) != NULL) {
+   TAILQ_REMOVE(&(session->sess_registrations), reg, reg_entry);
+   free(reg);
+   }
 
appl_close(&(session->sess_backend));
 
@@ -642,6 +667,7 @@ appl_agentx_register(struct appl_agentx_session *session, 
struct ax_pdu *pdu)
struct ber_oid oid;
enum appl_error error;
int subtree = 0;
+   struct appl_agentx_registration *reg;
 
timeout = pdu->ap_payload.ap_register.ap_timeout;
timeout = timeout != 0 ? timeout : session->sess_timeout != 0 ?
@@ -660,6 +686,13 @@ appl_agentx_register(struct appl_agentx_session *session, 
struct ax_pdu *pdu)
goto fail;
}
 
+   if ((reg = malloc(sizeof(*reg))) == NULL) {
+   log_warn("%s: Failed to register",
+   session->sess_backend.ab_name);
+   error = APPL_ERROR_PROCESSINGERROR;
+   goto fail;
+   }
+
error = appl_register(pdu->ap_context.aos_string, timeout,
pdu->ap_payload.ap_register.ap_priority, , 
pdu->ap_header.aph_flags & AX_PDU_FLAG_INSTANCE_REGISTRATION,
@@ -667,6 +700,26 @@ appl_agentx_register(struct appl_agentx_session *session, 
struct ax_pdu *pdu)
pdu->ap_payload.ap_register.ap_upper_bound,
&(session->sess_backend));
 
+   if (error == APPL_ERROR_NOERROR) {
+   reg->reg_index = appl_agentx_reg_index++;
+   (void)strlcpy(reg->reg_context, pdu->ap_context.aos_slen == 0 ?
+   "" : (const char *)pdu->ap_context.aos_string,
+   sizeof(reg->reg_context));
+   reg->reg_start = pdu->ap_payload.ap_register.ap_subtree;
+   reg->reg_rangesubid =
+   pdu->ap_payload.ap_register.ap_range_subid;
+   reg->reg_upperbound =
+   pdu->ap_payload.ap_register.ap_upper_bound;
+   reg->reg_priority = pdu->ap_payload.ap_register.ap_priority;
+   

snmpd [15/16]: When we have an error, all oids must be identical to the request

2023-10-17 Thread Martijn van Duren
RFC3416 section 4.2.1 (and others) tells us that if an error occurs the
varbindlist in the response must be identical to the original request.

There might be other edge-cases here, but let's at least make sure that
the OIDs haven't been tampered with.

OK?

martijn@

diff --git a/application.c b/application.c
index 53e793d..d98918f 100644
--- a/application.c
+++ b/application.c
@@ -1186,6 +1186,9 @@ appl_varbind_valid(struct appl_varbind *varbind,
int cmp;
int eomv = 0;
 
+   if (null)
+   next = 0;
+
if (varbind->av_value == NULL) {
if (!null) {
*errstr = "missing value";



snmpd [14/16]: Validate the returned error code

2023-10-17 Thread Martijn van Duren


Certain error codes are only intended for certain request-types. Add an
appl_error_valid() function to test for this.

OK?

martijn@

diff --git a/application.c b/application.c
index 6ddeb39..53e793d 100644
--- a/application.c
+++ b/application.c
@@ -130,6 +130,7 @@ void appl_request_downstream_timeout(int, short, void *);
 void appl_request_upstream_reply(struct appl_request_upstream *);
 int appl_varbind_valid(struct appl_varbind *, struct appl_varbind_internal *,
 int, int, int, const char **);
+int appl_error_valid(enum appl_error, enum snmp_pdutype);
 int appl_varbind_backend(struct appl_varbind_internal *);
 void appl_varbind_error(struct appl_varbind_internal *, enum appl_error);
 void appl_report(struct snmp_message *, int32_t, struct ber_oid *,
@@ -1069,6 +1070,11 @@ appl_response(struct appl_backend *backend, int32_t 
requestid,
next = pdutype == SNMP_C_GETNEXTREQ ||
pdutype == SNMP_C_GETBULKREQ;
origvb = dreq->ard_vblist;
+   if (!appl_error_valid(error, dreq->ard_requesttype)) {
+   log_warnx("%s: %"PRIu32" Invalid error",
+   backend->ab_name, requestid);
+   invalid = 1;
+   }
}
 
vb = vblist;
@@ -1295,6 +1301,37 @@ appl_varbind_valid(struct appl_varbind *varbind,
return 1;
 }
 
+int
+appl_error_valid(enum appl_error error, enum snmp_pdutype type)
+{
+   switch (error) {
+   case APPL_ERROR_NOERROR:
+   case APPL_ERROR_TOOBIG:
+   case APPL_ERROR_NOSUCHNAME:
+   case APPL_ERROR_GENERR:
+   return 1;
+   case APPL_ERROR_BADVALUE:
+   case APPL_ERROR_READONLY:
+   case APPL_ERROR_NOACCESS:
+   case APPL_ERROR_WRONGTYPE:
+   case APPL_ERROR_WRONGLENGTH:
+   case APPL_ERROR_WRONGENCODING:
+   case APPL_ERROR_WRONGVALUE:
+   case APPL_ERROR_NOCREATION:
+   case APPL_ERROR_INCONSISTENTVALUE:
+   case APPL_ERROR_RESOURCEUNAVAILABLE:
+   case APPL_ERROR_COMMITFAILED:
+   case APPL_ERROR_UNDOFAILED:
+   case APPL_ERROR_NOTWRITABLE:
+   case APPL_ERROR_INCONSISTENTNAME:
+   return type == SNMP_C_SETREQ;
+   case APPL_ERROR_AUTHORIZATIONERROR:
+   return type == SNMP_C_GETREQ || type == SNMP_C_SETREQ;
+   default:
+   return 0;
+   }
+}
+
 int
 appl_varbind_backend(struct appl_varbind_internal *ivb)
 {



snmpd [13/16]: registered instances must not return below OID

2023-10-17 Thread Martijn van Duren
If a backend registers as an instance it must never return OIDs below
their registration. Add a test for this in appl_varbind_valid().

OK?

martijn@

diff --git a/application.c b/application.c
index dfa7220..6ddeb39 100644
--- a/application.c
+++ b/application.c
@@ -128,8 +128,8 @@ void appl_request_upstream_resolve(struct 
appl_request_upstream *);
 void appl_request_downstream_send(struct appl_request_downstream *);
 void appl_request_downstream_timeout(int, short, void *);
 void appl_request_upstream_reply(struct appl_request_upstream *);
-int appl_varbind_valid(struct appl_varbind *, struct appl_varbind *, int, int,
-int, const char **);
+int appl_varbind_valid(struct appl_varbind *, struct appl_varbind_internal *,
+int, int, int, const char **);
 int appl_varbind_backend(struct appl_varbind_internal *);
 void appl_varbind_error(struct appl_varbind_internal *, enum appl_error);
 void appl_report(struct snmp_message *, int32_t, struct ber_oid *,
@@ -1073,9 +1073,9 @@ appl_response(struct appl_backend *backend, int32_t 
requestid,
 
vb = vblist;
for (i = 1; vb != NULL; vb = vb->av_next, i++) {
-if (!appl_varbind_valid(vb, origvb == NULL ?
-   NULL : &(origvb->avi_varbind), next,
-error != APPL_ERROR_NOERROR, backend->ab_range, )) {
+if (!appl_varbind_valid(vb, origvb == NULL ?  NULL : origvb,
+   next, error != APPL_ERROR_NOERROR, backend->ab_range,
+   )) {
smi_oid2string(&(vb->av_oid), oidbuf,
sizeof(oidbuf), 0);
log_warnx("%s: %"PRIu32" %s: %s",
@@ -1173,8 +1173,9 @@ appl_response(struct appl_backend *backend, int32_t 
requestid,
 }
 
 int
-appl_varbind_valid(struct appl_varbind *varbind, struct appl_varbind *request,
-int next, int null, int range, const char **errstr)
+appl_varbind_valid(struct appl_varbind *varbind,
+struct appl_varbind_internal *request, int next, int null, int range,
+const char **errstr)
 {
int cmp;
int eomv = 0;
@@ -1259,24 +1260,32 @@ appl_varbind_valid(struct appl_varbind *varbind, struct 
appl_varbind *request,
if (request == NULL)
return 1;
 
-   cmp = ober_oid_cmp(&(request->av_oid), &(varbind->av_oid));
-   if (next && !eomv) {
-   if (request->av_include) {
-   if (cmp > 0) {
-   *errstr = "oid not incrementing";
-   return 0;
+   cmp = ober_oid_cmp(&(request->avi_varbind.av_oid), &(varbind->av_oid));
+   if (next) {
+   if (request->avi_region->ar_instance &&
+   ober_oid_cmp(&(request->avi_region->ar_oid),
+   &(varbind->av_oid)) != 0) {
+   *errstr = "oid below instance";
+   return 0;
+   }
+   if (!eomv) {
+   if (request->avi_varbind.av_include) {
+   if (cmp > 0) {
+   *errstr = "oid not incrementing";
+   return 0;
+   }
+   } else {
+   if (cmp >= 0) {
+   *errstr = "oid not incrementing";
+   return 0;
+   }
}
-   } else {
-   if (cmp >= 0) {
-   *errstr = "oid not incrementing";
+   if (range && ober_oid_cmp(&(varbind->av_oid),
+   &(request->avi_varbind.av_oid_end)) > 0) {
+   *errstr = "end oid not honoured";
return 0;
}
}
-   if (range && ober_oid_cmp(&(varbind->av_oid),
-   &(request->av_oid_end)) > 0) {
-   *errstr = "end oid not honoured";
-   return 0;
-   }
} else {
if (cmp != 0) {
*errstr = "oids not equal";



snmpd [12/16]: Make ab_range in application_agentx explicit 1

2023-10-17 Thread Martijn van Duren
appl_agentx_session doesn't set ab_range explicitly to 1, and thus
relies on malloc randomness to set it. Sit it explicitly.

OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index 680725d..79900d6 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -548,6 +548,7 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
session->sess_backend.ab_cookie = session;
session->sess_backend.ab_retries = 0;
session->sess_backend.ab_fn = _agentx_functions;
+   session->sess_backend.ab_range = 1;
RB_INIT(&(session->sess_backend.ab_requests));
TAILQ_INSERT_TAIL(&(conn->conn_sessions), session, sess_conn_entry);
 



snmpd [11/16]: When a request results in EOMV we must return the requesting OID

2023-10-17 Thread Martijn van Duren
According to RFC3416 section 4.2.2 and 4.2.3 case "(2)" when an
endOfMibView is returned the OID must be identical to originally
requested OID. Currently this can fail when the original request
is in a !last registered region and all subsequent regions also
return EOMV.

Store the original OID and use that on EOMV.

OK?

martijn@

diff --git a/application.c b/application.c
index e780025..dfa7220 100644
--- a/application.c
+++ b/application.c
@@ -99,6 +99,7 @@ struct appl_varbind_internal {
enum appl_varbind_state avi_state;
struct appl_varbind avi_varbind;
struct appl_region *avi_region;
+   struct ber_oid avi_origid;
int16_t avi_index;
struct appl_request_upstream *avi_request_upstream;
struct appl_request_downstream *avi_request_downstream;
@@ -679,6 +680,8 @@ appl_processpdu(struct snmp_message *statereference, const 
char *ctxname,
}
ober_get_oid(varbind->be_sub,
&(ureq->aru_vblist[i].avi_varbind.av_oid));
+   ureq->aru_vblist[i].avi_origid =
+   ureq->aru_vblist[i].avi_varbind.av_oid;
if (i + 1 < ureq->aru_varbindlen) {
ureq->aru_vblist[i].avi_next =
&(ureq->aru_vblist[i + 1]);
@@ -1008,6 +1011,10 @@ appl_request_upstream_reply(struct appl_request_upstream 
*ureq)
vb = &(ureq->aru_vblist[i]);
vb->avi_varbind.av_next =
&(ureq->aru_vblist[i + 1].avi_varbind);
+   value = vb->avi_varbind.av_value;
+   if (value->be_class == BER_CLASS_CONTEXT &&
+   value->be_type == APPL_EXC_ENDOFMIBVIEW)
+   vb->avi_varbind.av_oid = vb->avi_origid;
}
 
ureq->aru_vblist[i - 1].avi_varbind.av_next = NULL;



snmpd [10/16]: Make retries on open session where connection is closed return early

2023-10-17 Thread Martijn van Duren
Here's a special case unlikely to be found in the wild:
When opening 2 sessions on an agentx connection (already unusual) and
registering 2 overlapping regions on the different sessions, e.g. by
differing in priority (even more unusual) and we close the underlying
connection with an outstanding request to the dominant region we will
call appl_agentx_free(), which sequentially closes all sessions.
If the session with the outstanding request is closed before the
second session the request is retried before said session is cleaned
up and it will try to send it over a conn_ax which at that point has
been set to NULL, resulting in a SIGSEGV.

Simply return early and let this second request be cancelled by the
cleanup of the second session.

OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index 2231d4c..680725d 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -712,6 +712,9 @@ appl_agentx_get(struct appl_backend *backend, int32_t 
transactionid,
struct ax_searchrange *srl;
size_t i, j, nsr;
 
+   if (session->sess_conn->conn_ax == NULL)
+   return;
+
for (nsr = 0, vb = vblist; vb != NULL; vb = vb->av_next)
nsr++;
 
@@ -760,6 +763,9 @@ appl_agentx_getnext(struct appl_backend *backend, int32_t 
transactionid,
struct ax_searchrange *srl;
size_t i, j, nsr;
 
+   if (session->sess_conn->conn_ax == NULL)
+   return;
+
for (nsr = 0, vb = vblist; vb != NULL; vb = vb->av_next)
nsr++;
 



snmpd [9/16]: Fix range handling with appl_unregister

2023-10-17 Thread Martijn van Duren
Right now (un)registering a region with range_subid set to !0 will
fail. Apparently nothing in the wild uses this, but let's fix it.

This is the unregister part.

OK? martijn@

diff --git a/application.c b/application.c
index f8709b8..e780025 100644
--- a/application.c
+++ b/application.c
@@ -115,6 +115,8 @@ struct snmp_target_mib {
 enum appl_error appl_region(struct appl_context *, uint32_t, uint8_t,
 struct ber_oid *, int, int, struct appl_backend *);
 void appl_region_free(struct appl_context *, struct appl_region *);
+enum appl_error appl_region_unregister_match(struct appl_context *, uint8_t,
+struct ber_oid *, char *, struct appl_backend *, int);
 struct appl_region *appl_region_find(struct appl_context *,
 const struct ber_oid *);
 struct appl_region *appl_region_next(struct appl_context *,
@@ -400,9 +402,10 @@ enum appl_error
 appl_unregister(const char *ctxname, uint8_t priority, struct ber_oid *oid,
 uint8_t range_subid, uint32_t upper_bound, struct appl_backend *backend)
 {
-   struct appl_region *region, search;
struct appl_context *ctx;
char oidbuf[1024], subidbuf[11];
+   enum appl_error error;
+   uint32_t lower_bound;
size_t i;
 
oidbuf[0] = '\0';
@@ -444,34 +447,45 @@ appl_unregister(const char *ctxname, uint8_t priority, 
struct ber_oid *oid,
return APPL_ERROR_PARSEERROR;
}
 
-   if (range_subid > oid->bo_n) {
+   if (range_subid == 0)
+   return appl_region_unregister_match(ctx, priority, oid, oidbuf,
+   backend, 1);
+
+   range_subid--;
+   if (range_subid >= oid->bo_n) {
log_warnx("%s: Can't unregiser %s: range_subid too large",
backend->ab_name, oidbuf);
return APPL_ERROR_PARSEERROR;
}
-   if (range_subid != 0 && oid->bo_id[range_subid] >= upper_bound) {
-   log_warnx("%s: Can't unregister %s: upper bound smaller or "
-   "equal to range_subid", backend->ab_name, oidbuf);
+   if (oid->bo_id[range_subid] > upper_bound) {
+   log_warnx("%s: Can't unregister %s: upper bound smaller than "
+   "range_subid", backend->ab_name, oidbuf);
return APPL_ERROR_PARSEERROR;
}
 
+   lower_bound = oid->bo_id[range_subid];
+   do {
+   if ((error = appl_region_unregister_match(ctx, priority, oid,
+   oidbuf, backend, 0)) != APPL_ERROR_NOERROR)
+   return error;
+   } while (oid->bo_id[range_subid]++ != upper_bound);
+
+   oid->bo_id[range_subid] = lower_bound;
+   do {
+   (void)appl_region_unregister_match(ctx, priority, oid, oidbuf,
+   backend, 1);
+   } while (oid->bo_id[range_subid]++ != upper_bound);
+
+   return APPL_ERROR_NOERROR;
+}
+
+enum appl_error
+appl_region_unregister_match(struct appl_context *ctx, uint8_t priority,
+struct ber_oid *oid, char *oidbuf, struct appl_backend *backend, int 
dofree)
+{
+   struct appl_region *region, search;
+
search.ar_oid = *oid;
-   while (range_subid != 0 &&
-   search.ar_oid.bo_id[range_subid] != upper_bound) {
-   region = RB_FIND(appl_regions, &(ctx->ac_regions), );
-   while (region != NULL && region->ar_priority < priority)
-   region = region->ar_next;
-   if (region == NULL || region->ar_priority != priority) {
-   log_warnx("%s: Can't unregister %s: region not found",
-   backend->ab_name, oidbuf);
-   return APPL_ERROR_UNKNOWNREGISTRATION;
-   }
-   if (region->ar_backend != backend) {
-   log_warnx("%s: Can't unregister %s: region not owned "
-   "by backend", backend->ab_name, oidbuf);
-   return APPL_ERROR_UNKNOWNREGISTRATION;
-   }
-   }
region = RB_FIND(appl_regions, &(ctx->ac_regions), );
while (region != NULL && region->ar_priority < priority)
region = region->ar_next;
@@ -485,20 +499,8 @@ appl_unregister(const char *ctxname, uint8_t priority, 
struct ber_oid *oid,
"by backend", backend->ab_name, oidbuf);
return APPL_ERROR_UNKNOWNREGISTRATION;
}
-
-   search.ar_oid = *oid;
-   while (range_subid != 0 &&
-   search.ar_oid.bo_id[range_subid] != upper_bound) {
-   region = RB_FIND(appl_regions, &(ctx->ac_regions), );
-   while (region != NULL && region->ar_priority != priority)
-   region = region->ar_next;
+   if (dofree)
appl_region_free(ctx, region);
-   }
-   region = RB_FIND(appl_regions, &(ctx->ac_regions), );
-   while (region != NULL && region->ar_priority != priority)
-   region = region->ar_next;
-   appl_region_free(ctx, 

snmpd [8/16]: Fix range handling with appl_register

2023-10-17 Thread Martijn van Duren
Right now (un)registering a region with range_subid set to !0 will
fail. Apparently nothing in the wild uses this, but let's fix it.

This is the register part.

OK?

martijn@

diff --git a/application.c b/application.c
index a02260b..f8709b8 100644
--- a/application.c
+++ b/application.c
@@ -347,28 +347,29 @@ appl_register(const char *ctxname, uint32_t timeout, 
uint8_t priority,
backend->ab_name, oidbuf);
return APPL_ERROR_PARSEERROR;
}
-   if (range_subid > oid->bo_n) {
+
+   if (range_subid == 0)
+   return appl_region(ctx, timeout, priority, oid, instance,
+   subtree, backend);
+
+   range_subid--;
+   if (range_subid >= oid->bo_n) {
log_warnx("%s: Can't register %s: range_subid too large",
backend->ab_name, oidbuf);
return APPL_ERROR_PARSEERROR;
}
-   if (range_subid != 0 && oid->bo_id[range_subid] >= upper_bound) {
-   log_warnx("%s: Can't register %s: upper bound smaller or equal "
-   "to range_subid", backend->ab_name, oidbuf);
+   if (oid->bo_id[range_subid] > upper_bound) {
+   log_warnx("%s: Can't register %s: upper bound smaller than "
+   "range_subid", backend->ab_name, oidbuf);
return APPL_ERROR_PARSEERROR;
}
-   if (range_subid != 0)
-   lower_bound = oid->bo_id[range_subid];
-
-   if (range_subid == 0)
-   return appl_region(ctx, timeout, priority, oid, instance,
-   subtree, backend);
 
+   lower_bound = oid->bo_id[range_subid];
do {
if ((error = appl_region(ctx, timeout, priority, oid, instance,
subtree, backend)) != APPL_ERROR_NOERROR)
goto fail;
-   } while (oid->bo_id[range_subid] != upper_bound);
+   } while (oid->bo_id[range_subid]++ != upper_bound);
if ((error = appl_region(ctx, timeout, priority, oid, instance, subtree,
backend)) != APPL_ERROR_NOERROR)
goto fail;



snmpd [7/16]: Treat agentx-close-pdu with reasonByManager as a parseerror

2023-10-17 Thread Martijn van Duren


RFC2741 section 6.2.2 says that reasonByManager can only be used by the
agentx master. Treat this reason as a parseerror.

OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index d1efae2..2231d4c 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -576,16 +576,29 @@ appl_agentx_close(struct appl_agentx_session *session, 
struct ax_pdu *pdu)
 {
struct appl_agentx_connection *conn = session->sess_conn;
char name[100];
+   enum appl_error error = APPL_ERROR_NOERROR;
 
strlcpy(name, session->sess_backend.ab_name, sizeof(name));
-   appl_agentx_session_free(session);
-   log_info("%s: Closed by subagent (%s)", name,
-   ax_closereason2string(pdu->ap_payload.ap_close.ap_reason));
+   if (pdu->ap_payload.ap_close.ap_reason == AX_CLOSE_BYMANAGER) {
+   log_warnx("%s: Invalid close reason", name);
+   error = APPL_ERROR_PARSEERROR;
+   } else {
+   appl_agentx_session_free(session);
+   log_info("%s: Closed by subagent (%s)", name,
+   ax_closereason2string(pdu->ap_payload.ap_close.ap_reason));
+   }
 
ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
-   smi_getticks(), APPL_ERROR_NOERROR, 0, NULL, 0);
+   smi_getticks(), error, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
+   if (error == APPL_ERROR_NOERROR)
+   return;
+
+   appl_agentx_forceclose(&(session->sess_backend),
+   APPL_CLOSE_REASONPARSEERROR);
+   if (TAILQ_EMPTY(&(conn->conn_sessions)))
+   appl_agentx_free(conn, APPL_CLOSE_REASONOTHER);
 }
 
 void



snmpd [6/16]: support close reason for appl_agentx_free

2023-10-17 Thread Martijn van Duren
appl_agentx_free() closes any potential open sessions before closing the
connection and cleaning up. This function is called from multiple
contexts and the current APPL_CLOSE_REASONSHUTDOWN is not always
applicable. Add a second reason parameter that can be passed onto
appl_agentx_forceclose().

OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index 6a4ed49..d1efae2 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -77,7 +77,7 @@ struct appl_agentx_session {
 
 void appl_agentx_listen(struct agentx_master *);
 void appl_agentx_accept(int, short, void *);
-void appl_agentx_free(struct appl_agentx_connection *);
+void appl_agentx_free(struct appl_agentx_connection *, enum appl_close_reason);
 void appl_agentx_recv(int, short, void *);
 void appl_agentx_open(struct appl_agentx_connection *, struct ax_pdu *);
 void appl_agentx_close(struct appl_agentx_session *, struct ax_pdu *);
@@ -178,7 +178,7 @@ appl_agentx_shutdown(void)
struct appl_agentx_connection *conn, *tconn;
 
RB_FOREACH_SAFE(conn, appl_agentx_conns, _agentx_conns, tconn)
-   appl_agentx_free(conn);
+   appl_agentx_free(conn, APPL_CLOSE_REASONSHUTDOWN);
 }
 
 void
@@ -249,7 +249,8 @@ appl_agentx_backend(int fd)
 }
 
 void
-appl_agentx_free(struct appl_agentx_connection *conn)
+appl_agentx_free(struct appl_agentx_connection *conn,
+enum appl_close_reason reason)
 {
struct appl_agentx_session *session;
 
@@ -261,7 +262,7 @@ appl_agentx_free(struct appl_agentx_connection *conn)
appl_agentx_session_free(session);
else
appl_agentx_forceclose(&(session->sess_backend),
-   APPL_CLOSE_REASONSHUTDOWN);
+   reason);
}
 
RB_REMOVE(appl_agentx_conns, _agentx_conns, conn);
@@ -294,7 +295,8 @@ appl_agentx_recv(int fd, short event, void *cookie)
ax_free(conn->conn_ax);
conn->conn_ax = NULL;
}
-   appl_agentx_free(conn);
+   appl_agentx_free(conn, errno == EPROTO ?
+   APPL_CLOSE_REASONPROTOCOLERROR : APPL_CLOSE_REASONOTHER);
return;
}
 
@@ -458,7 +460,7 @@ appl_agentx_recv(int fd, short event, void *cookie)
appl_agentx_forceclose(&(session->sess_backend),
APPL_CLOSE_REASONPARSEERROR);
if (TAILQ_EMPTY(&(conn->conn_sessions)))
-   appl_agentx_free(conn);
+   appl_agentx_free(conn, APPL_CLOSE_REASONOTHER);
 }
 
 void
@@ -847,7 +849,7 @@ appl_agentx_send(int fd, short event, void *cookie)
log_warn("AgentX(%"PRIu32")", conn->conn_id);
ax_free(conn->conn_ax);
conn->conn_ax = NULL;
-   appl_agentx_free(conn);
+   appl_agentx_free(conn, APPL_CLOSE_REASONOTHER);
return;
case 0:
return;



snmpd [5/16]: Check context existence in appl_agentx_recv

2023-10-17 Thread Martijn van Duren
application.c checks the context where applicable, but not every
agentx-pdu goes through there (e.g. agentx-ping-pdu). Make sure
we always check the context in appl_agentx_recv()

OK?

martijn@

diff --git a/application.c b/application.c
index dd92864..a02260b 100644
--- a/application.c
+++ b/application.c
@@ -175,7 +175,7 @@ appl_shutdown(void)
}
 }
 
-static struct appl_context *
+struct appl_context *
 appl_context(const char *name, int create)
 {
struct appl_context *ctx;
diff --git a/application.h b/application.h
index 8b2c567..949bbde 100644
--- a/application.h
+++ b/application.h
@@ -121,6 +121,7 @@ struct appl_backend {
 void appl(void);
 void appl_init(void);
 void appl_shutdown(void);
+struct appl_context *appl_context(const char *, int);
 enum appl_error appl_register(const char *, uint32_t, uint8_t, struct ber_oid 
*,
 int, int, uint8_t, uint32_t, struct appl_backend *);
 enum appl_error appl_unregister(const char *, uint8_t, struct ber_oid *,
diff --git a/application_agentx.c b/application_agentx.c
index c11b666..6a4ed49 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -370,6 +370,12 @@ appl_agentx_recv(int fd, short event, void *cookie)
error = APPL_ERROR_PARSEERROR;
goto fail;
}
+   if (appl_context(pdu->ap_context.aos_string, 0) == 0) {
+   log_warnx("%s: %s: Unsupported context",
+   name, ax_pdutype2string(pdu->ap_header.aph_flags));
+   error = APPL_ERROR_UNSUPPORTEDCONTEXT;
+   goto fail;
+   }
}
switch (pdu->ap_header.aph_type) {
case AX_PDU_TYPE_OPEN:



snmpd [4/16]: check agentx-pdu-header flags for validity

2023-10-17 Thread Martijn van Duren
RFC2741 section 6.1 specifies which PDUs can contain which header flags.
Check that that incoming agentx PDUs have valid flags in
appl_agentx_recv(). While here I cleaned up a few log messages some
minor restructuring to prevent the function growing too large.

OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index 9cc98eb..c11b666 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -276,13 +276,16 @@ void
 appl_agentx_recv(int fd, short event, void *cookie)
 {
struct appl_agentx_connection *conn = cookie;
-   struct appl_agentx_session *session;
+   struct appl_agentx_session *session = NULL;
struct ax_pdu *pdu;
+   enum appl_error error;
+   char name[100];
 
+   snprintf(name, sizeof(name), "AgentX(%"PRIu32")", conn->conn_id);
if ((pdu = ax_recv(conn->conn_ax)) == NULL) {
if (errno == EAGAIN)
return;
-   log_warn("AgentX(%"PRIu32")", conn->conn_id);
+   log_warn("%s", name);
/*
 * Either the connection is dead, or we had garbage on the line.
 * Both make sure we can't continue on this stream.
@@ -306,16 +309,12 @@ appl_agentx_recv(int fd, short event, void *cookie)
break;
}
if (session == NULL) {
-   log_warnx("AgentX(%"PRIu32"): Session %"PRIu32" not "
-   "found for request", conn->conn_id,
-   pdu->ap_header.aph_sessionid);
-   ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
-   pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid, smi_getticks(),
-   APPL_ERROR_NOTOPEN, 0, NULL, 0);
-   appl_agentx_send(-1, EV_WRITE, conn);
+   log_warnx("%s: Session %"PRIu32" not found for request",
+   name, pdu->ap_header.aph_sessionid);
+   error = APPL_ERROR_NOTOPEN;
goto fail;
}
+   strlcpy(name, session->sess_backend.ab_name, sizeof(name));
/*
 * RFC2741 section 7.1.1 bullet 4 is unclear on what byte order
 * the response should be. My best guess is that it makes more
@@ -327,6 +326,51 @@ appl_agentx_recv(int fd, short event, void *cookie)
 */
}
 
+   if (pdu->ap_header.aph_flags & AX_PDU_FLAG_INSTANCE_REGISTRATION) {
+   if (pdu->ap_header.aph_type != AX_PDU_TYPE_REGISTER) {
+   log_warnx("%s: %s: Invalid INSTANCE_REGISTRATION flag",
+   name, ax_pdutype2string(pdu->ap_header.aph_flags));
+   error = APPL_ERROR_PARSEERROR;
+   goto fail;
+   }
+   }
+   if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NEW_INDEX) {
+   if (pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXALLOCATE &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXDEALLOCATE) {
+   log_warnx("%s: %s: Invalid NEW_INDEX flag", name,
+   ax_pdutype2string(pdu->ap_header.aph_flags));
+   error = APPL_ERROR_PARSEERROR;
+   goto fail;
+   }
+   }
+   if (pdu->ap_header.aph_flags & AX_PDU_FLAG_ANY_INDEX) {
+   if (pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXALLOCATE &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXDEALLOCATE) {
+   log_warnx("%s: %s: Invalid ANY_INDEX flag", name,
+   ax_pdutype2string(pdu->ap_header.aph_flags));
+   error = APPL_ERROR_PARSEERROR;
+   goto fail;
+   }
+   }
+   if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT) {
+   if (pdu->ap_header.aph_type != AX_PDU_TYPE_REGISTER &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_UNREGISTER &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_ADDAGENTCAPS &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_REMOVEAGENTCAPS &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_GET &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_GETNEXT &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_GETBULK &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXALLOCATE &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXDEALLOCATE &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_NOTIFY &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_TESTSET &&
+   pdu->ap_header.aph_type != AX_PDU_TYPE_PING) {
+   log_warnx("%s: %s: Invalid NON_DEFAULT_CONTEXT flag",
+   name, 

snmpd [3/16]: Distinguish between parseerror and openfailed for agentx-open-pdu

2023-10-17 Thread Martijn van Duren
RFC2741 section 7.1.1 tells us that if a pdu can't be parsed we must
return a parseerror. Section 7.1 gives an example of "An unrecognized
value is encountered". The spec is vague is a bit vague on what
constitutes a parseerror, vs a protocol error, so I don't want to
muddle too much with that part, but let's at least return an
appropriate error when a client sends invalid data in the open request.

The spec clearly states that any error, which is not a parseerror must
be a openfailed error. So no processingerrors.

OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index 0d73e08..9cc98eb 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -411,9 +411,11 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
struct appl_agentx_session *session;
struct ber_oid oid;
char oidbuf[1024];
+   enum appl_error error = APPL_ERROR_NOERROR;
 
if ((session = malloc(sizeof(*session))) == NULL) {
log_warn(NULL);
+   error = APPL_ERROR_OPENFAILED;
goto fail;
}
session->sess_descr.aos_string = NULL;
@@ -432,12 +434,14 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
} else if (pdu->ap_payload.ap_open.ap_oid.aoi_idlen == 1) {
log_warnx("AgentX(%"PRIu32"): Invalid oid: Open Failed",
conn->conn_id);
+   error = APPL_ERROR_PARSEERROR;
goto fail;
}
/* RFC 2742 agentxSessionDescr */
if (pdu->ap_payload.ap_open.ap_descr.aos_slen > 255) {
log_warnx("AgentX(%"PRIu32"): Invalid descr (too long): Open "
"Failed", conn->conn_id);
+   error = APPL_ERROR_PARSEERROR;
goto fail;
}
/*
@@ -451,6 +455,7 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
pdu->ap_payload.ap_open.ap_descr.aos_string, 0) == (size_t)-1) {
log_warnx("AgentX(%"PRIu32"): Invalid descr (not UTF-8): "
"Open Failed", conn->conn_id);
+   error = APPL_ERROR_PARSEERROR;
goto fail;
}
 
@@ -463,6 +468,7 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
if (session->sess_descr.aos_string == NULL) {
log_warn("AgentX(%"PRIu32"): strdup: Open Failed",
conn->conn_id);
+   error = APPL_ERROR_OPENFAILED;
goto fail;
}
}
@@ -478,6 +484,7 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
conn->conn_id, session->sess_id) == -1) {
log_warn("AgentX(%"PRIu32"): asprintf: Open Failed",
conn->conn_id);
+   error = APPL_ERROR_OPENFAILED;
goto fail;
}
session->sess_backend.ab_cookie = session;
@@ -499,7 +506,7 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
return;
  fail:
ax_response(conn->conn_ax, 0, pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid, 0, APPL_ERROR_OPENFAILED, 0, NULL, 0);
+   pdu->ap_header.aph_packetid, 0, error, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
if (session != NULL)
free(session->sess_descr.aos_string);



snmpd [2.2/16]: Don't set NON_DEFAULT_CONTEXT for agentx-response-pdu

2023-10-17 Thread Martijn van Duren
> According to RFC2741 section 6.1.1 an agentx-response-pdu shouldn't have
> the NON_DEFAULT_CONTEXT set. Remove the argument from ax_response().

Here's the libagentx counterpart.

OK?

martijn@

Index: agentx.c
===
RCS file: /cvs/src/lib/libagentx/agentx.c,v
retrieving revision 1.22
diff -u -p -r1.22 agentx.c
--- agentx.c27 Dec 2022 17:10:05 -  1.22
+++ agentx.c9 Oct 2023 20:24:40 -
@@ -2733,8 +2733,7 @@ agentx_get_finalize(struct agentx_get *a
free(logmsg);
 
if (ax_response(ax->ax_ax, axs->axs_id, axg->axg_transactionid,
-   axg->axg_packetid, AGENTX_CONTEXT_CTX(axc), 0, error, index,
-   vbl, nvarbind) == -1) {
+   axg->axg_packetid, 0, error, index, vbl, nvarbind) == -1) {
agentx_log_axg_warn(axg, "Couldn't parse request");
agentx_reset(ax);
} else
@@ -4041,7 +4040,6 @@ agentx_read(struct agentx *ax)
if (ax_response(ax->ax_ax, axs->axs_id,
pdu->ap_header.aph_transactionid,
pdu->ap_header.aph_packetid,
-   axc == NULL ? NULL : AGENTX_CONTEXT_CTX(axc),
0, error, 1, NULL, 0) == -1)
agentx_log_axc_warn(axc,
"transaction: %u packetid: %u: failed to send "
Index: ax.c
===
RCS file: /cvs/src/lib/libagentx/ax.c,v
retrieving revision 1.8
diff -u -p -r1.8 ax.c
--- ax.c24 Oct 2021 17:43:38 -  1.8
+++ ax.c9 Oct 2023 20:24:40 -
@@ -553,11 +553,11 @@ ax_unregister(struct ax *ax, uint32_t se
 
 int
 ax_response(struct ax *ax, uint32_t sessionid, uint32_t transactionid,
-uint32_t packetid, struct ax_ostring *context, uint32_t sysuptime,
-uint16_t error, uint16_t index, struct ax_varbind *vblist, size_t nvb)
+uint32_t packetid, uint32_t sysuptime, uint16_t error, uint16_t index,
+struct ax_varbind *vblist, size_t nvb)
 {
if (ax_pdu_header(ax, AX_PDU_TYPE_RESPONSE, 0, sessionid,
-   transactionid, packetid, context) == -1)
+   transactionid, packetid, NULL) == -1)
return -1;
 
if (ax_pdu_add_uint32(ax, sysuptime) == -1 ||
Index: ax.h
===
RCS file: /cvs/src/lib/libagentx/ax.h,v
retrieving revision 1.4
diff -u -p -r1.4 ax.h
--- ax.h2 Jan 2021 01:06:31 -   1.4
+++ ax.h9 Oct 2023 20:24:40 -
@@ -220,8 +220,7 @@ uint32_t ax_register(struct ax *, uint8_
 uint32_t ax_unregister(struct ax *, uint32_t, struct ax_ostring *,
 uint8_t, uint8_t, struct ax_oid *, uint32_t);
 int ax_response(struct ax *, uint32_t, uint32_t, uint32_t,
-struct ax_ostring *, uint32_t, uint16_t, uint16_t,
-struct ax_varbind *, size_t);
+uint32_t, uint16_t, uint16_t, struct ax_varbind *, size_t);
 void ax_pdu_free(struct ax_pdu *);
 void ax_varbind_free(struct ax_varbind *);
 const char *ax_error2string(enum ax_pdu_error);



Re: snmpd [1.1/16]: Don't overflow oid in agentx parser

2023-10-17 Thread Martijn van Duren
> Currently ax.c doesn't check the maximum length of an OID ax_pdutooid.
> This can lead to a buffer overflow. Even though it must be fixed, I
> don't think there's a big risk here, since an attacker would need to have
> access to the agentx socket, which by default is disabled and defaults
> to root:_agentx when enabled.

Here's the libagentx counterpart.

OK?

martijn@

Index: ax.c
===
RCS file: /cvs/src/lib/libagentx/ax.c,v
retrieving revision 1.8
diff -u -p -r1.8 ax.c
--- ax.c24 Oct 2021 17:43:38 -  1.8
+++ ax.c9 Oct 2023 20:14:13 -
@@ -1262,6 +1262,8 @@ ax_pdutooid(struct ax_pdu_header *header
}
buf++;
oid->aoi_include = *buf;
+   if (oid->aoi_idlen > AX_OID_MAX_LEN)
+   goto fail;
for (buf += 2; i < oid->aoi_idlen; i++, buf += 4)
oid->aoi_id[i] = ax_pdutoh32(header, buf);
 



snmpd [2.1/16]: Don't set NON_DEFAULT_CONTEXT for agentx-response-pdu

2023-10-17 Thread Martijn van Duren
According to RFC2741 section 6.1.1 an agentx-response-pdu shouldn't have
the NON_DEFAULT_CONTEXT set. Remove the argument from ax_response().

OK?

martijn@

diff --git a/application_agentx.c b/application_agentx.c
index c7a2a26..0d73e08 100644
--- a/application_agentx.c
+++ b/application_agentx.c
@@ -311,8 +311,7 @@ appl_agentx_recv(int fd, short event, void *cookie)
pdu->ap_header.aph_sessionid);
ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid,
-   &(pdu->ap_context), smi_getticks(),
+   pdu->ap_header.aph_packetid, smi_getticks(),
APPL_ERROR_NOTOPEN, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
goto fail;
@@ -370,8 +369,8 @@ appl_agentx_recv(int fd, short event, void *cookie)
case AX_PDU_TYPE_PING:
ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid, &(pdu->ap_context),
-   smi_getticks(), APPL_ERROR_NOERROR, 0, NULL, 0);
+   pdu->ap_header.aph_packetid, smi_getticks(),
+   APPL_ERROR_NOERROR, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
break;
case AX_PDU_TYPE_INDEXALLOCATE:
@@ -380,8 +379,8 @@ appl_agentx_recv(int fd, short event, void *cookie)
ax_pdutype2string(pdu->ap_header.aph_type));
ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid, &(pdu->ap_context),
-   smi_getticks(), APPL_ERROR_PROCESSINGERROR, 1,
+   pdu->ap_header.aph_packetid, smi_getticks(),
+   APPL_ERROR_PROCESSINGERROR, 1,
pdu->ap_payload.ap_vbl.ap_varbind,
pdu->ap_payload.ap_vbl.ap_nvarbind);
appl_agentx_send(-1, EV_WRITE, conn);
@@ -392,8 +391,8 @@ appl_agentx_recv(int fd, short event, void *cookie)
ax_pdutype2string(pdu->ap_header.aph_type));
ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid, &(pdu->ap_context),
-   smi_getticks(), APPL_ERROR_PROCESSINGERROR, 1,
+   pdu->ap_header.aph_packetid, smi_getticks(),
+   APPL_ERROR_PROCESSINGERROR, 1,
NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
break;
@@ -492,16 +491,15 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
struct ax_pdu *pdu)
log_info("%s: %s %s: Open", session->sess_backend.ab_name, oidbuf,
session->sess_descr.aos_string);
 
-   ax_response(conn->conn_ax, session->sess_id, 
pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid, NULL, smi_getticks(), 
APPL_ERROR_NOERROR, 0,
-   NULL, 0);
+   ax_response(conn->conn_ax, session->sess_id,
+   pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
+   smi_getticks(), APPL_ERROR_NOERROR, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
 
return;
  fail:
ax_response(conn->conn_ax, 0, pdu->ap_header.aph_transactionid,
-   pdu->ap_header.aph_packetid, NULL, 0, APPL_ERROR_OPENFAILED, 0,
-   NULL, 0);
+   pdu->ap_header.aph_packetid, 0, APPL_ERROR_OPENFAILED, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
if (session != NULL)
free(session->sess_descr.aos_string);
@@ -521,7 +519,7 @@ appl_agentx_close(struct appl_agentx_session *session, 
struct ax_pdu *pdu)
 
ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
-   &(pdu->ap_context), smi_getticks(), APPL_ERROR_NOERROR, 0, NULL, 0);
+   smi_getticks(), APPL_ERROR_NOERROR, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, conn);
 }
 
@@ -593,7 +591,7 @@ appl_agentx_register(struct appl_agentx_session *session, 
struct ax_pdu *pdu)
  fail:
ax_response(session->sess_conn->conn_ax, session->sess_id,
pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
-   &(pdu->ap_context), smi_getticks(), error, 0, NULL, 0);
+   smi_getticks(), error, 0, NULL, 0);
appl_agentx_send(-1, EV_WRITE, session->sess_conn);
 }
 
@@ -620,7 +618,7 @@ appl_agentx_unregister(struct appl_agentx_session *session, 
struct ax_pdu *pdu)
  fail:
ax_response(session->sess_conn->conn_ax, session->sess_id,
pdu->ap_header.aph_transactionid, 

snmpd [1.1/16]: Don't overflow oid in agentx parser

2023-10-17 Thread Martijn van Duren
Currently ax.c doesn't check the maximum length of an OID ax_pdutooid.
This can lead to a buffer overflow. Even though it must be fixed, I
don't think there's a big risk here, since an attacker would need to have
access to the agentx socket, which by default is disabled and defaults
to root:_agentx when enabled.

OK?

martijn@

diff --git a/ax.c b/ax.c
index 63add68..27580a6 100644
--- a/ax.c
+++ b/ax.c
@@ -1442,6 +1442,8 @@ ax_pdutooid(struct ax_pdu_header *header, struct ax_oid 
*oid,
}
buf++;
oid->aoi_include = *buf;
+   if (oid->aoi_idlen > AX_OID_MAX_LEN)
+   goto fail;
for (buf += 2; i < oid->aoi_idlen; i++, buf += 4)
oid->aoi_id[i] = ax_pdutoh32(header, buf);
 



Prevent off-by-one accounting hang in out-of-swap situations

2023-10-17 Thread Martin Pieuchot
Diff below makes out-of-swap checks more robust.

When a system is low on swap, two variables are used to adapt the
behavior of the page daemon and fault handler:

`swpginuse'
indicates how much swap space is being currently used

`swpgonly'
indicates how much swap space stores content of pages that are no
longer living in memory.

The diff below changes the heuristic to detect if the system is currently
out-of-swap.  In my tests it makes the system more stable by preventing
hangs.  It prevents from hangs that occur when the system has more than 99%
of it swap space filled.  When this happen, the checks using the variables
above to figure out if we are out-of-swap might never be true because of:

- Races between the fault-handler and the accounting of the page daemon
  due to asynchronous swapping

- The swap partition being never completely allocated (bad pages, 
  off-by-one, rounding error, size of a swap cluster...)

- Possible off-by-one accounting errors in swap space

So I'm adapting uvm_swapisfull() to return true as soon as more than
99% of the swap space is filled with pages which are no longer in memory.

I also introduce uvm_swapisfilled() to prevent later failures if there is
less than a cluster of space available (the minimum we try to swap out).
This prevent deadlocking if a few slots (pg_flags & PQ_SWAPBACKED) &&
-   uvmexp.swpginuse == uvmexp.swpages) {
+   if ((p->pg_flags & PQ_SWAPBACKED) && uvm_swapisfilled())
uvmpd_dropswap(p);
-   }
 
/*
 * the page we are looking at is dirty.   we must
@@ -917,9 +914,7 @@ uvmpd_scan(struct uvm_pmalloc *pma, struct 
uvm_constraint_range *constraint)
 */
free = uvmexp.free - BUFPAGES_DEFICIT;
swap_shortage = 0;
-   if (free < uvmexp.freetarg &&
-   uvmexp.swpginuse == uvmexp.swpages &&
-   !uvm_swapisfull() &&
+   if (free < uvmexp.freetarg && uvm_swapisfilled() && !uvm_swapisfull() &&
pages_freed == 0) {
swap_shortage = uvmexp.freetarg - free;
}
diff --git sys/uvm/uvm_swap.c sys/uvm/uvm_swap.c
index 27963259eba..913b2366a7c 100644
--- sys/uvm/uvm_swap.c
+++ sys/uvm/uvm_swap.c
@@ -1516,8 +1516,30 @@ ReTry:   /* XXXMRG */
 }
 
 /*
- * uvm_swapisfull: return true if all of available swap is allocated
- * and in use.
+ * uvm_swapisfilled: return true if the amount of free space in swap is
+ * smaller than the size of a cluster.
+ *
+ * As long as some swap slots are being used by pages currently in memory,
+ * it is possible to reuse them.  Even if the swap space has been completly
+ * filled we do not consider it full.
+ */
+int
+uvm_swapisfilled(void)
+{
+   int result;
+
+   mtx_enter(_swap_data_lock);
+   KASSERT(uvmexp.swpginuse <= uvmexp.swpages);
+   result = (uvmexp.swpginuse + SWCLUSTPAGES) >= uvmexp.swpages;
+   mtx_leave(_swap_data_lock);
+
+   return result;
+}
+
+/*
+ * uvm_swapisfull: return true if the amount of pages only in swap
+ * accounts for more than 99% of the total swap space.
+ *
  */
 int
 uvm_swapisfull(void)
@@ -1526,7 +1548,7 @@ uvm_swapisfull(void)
 
mtx_enter(_swap_data_lock);
KASSERT(uvmexp.swpgonly <= uvmexp.swpages);
-   result = (uvmexp.swpgonly == uvmexp.swpages);
+   result = (uvmexp.swpgonly >= (uvmexp.swpages * 99 / 100));
mtx_leave(_swap_data_lock);
 
return result;
diff --git sys/uvm/uvm_swap.h sys/uvm/uvm_swap.h
index 9904fe58cd7..f60237405ca 100644
--- sys/uvm/uvm_swap.h
+++ sys/uvm/uvm_swap.h
@@ -42,6 +42,7 @@ int   uvm_swap_put(int, struct vm_page **, 
int, int);
 intuvm_swap_alloc(int *, boolean_t);
 void   uvm_swap_free(int, int);
 void   uvm_swap_markbad(int, int);
+intuvm_swapisfilled(void);
 intuvm_swapisfull(void);
 void   uvm_swap_freepages(struct vm_page **, int);
 #ifdef HIBERNATE
diff --git sys/uvm/uvmexp.h sys/uvm/uvmexp.h
index de5f5fa367c..144494b73ff 100644
--- sys/uvm/uvmexp.h
+++ sys/uvm/uvmexp.h
@@ -83,7 +83,7 @@ struct uvmexp {
/* swap */
int nswapdev;   /* [S] number of configured swap devices in system */
int swpages;/* [S] number of PAGE_SIZE'ed swap pages */
-   int swpginuse;  /* [K] number of swap pages in use */
+   int swpginuse;  /* [S] number of swap pages in use */
int swpgonly;   /* [a] number of swap pages in use, not also in RAM */
int nswget; /* [a] number of swap pages moved from disk to RAM */
int nanon;  /* XXX number total of anon's in system */



Re: small fix in uvmpd_scan_inactive()

2023-10-17 Thread Theo Buehler
On Tue, Oct 17, 2023 at 12:41:57PM +0200, Martin Pieuchot wrote:
> Diff below merges two equivalent if blocks.  No functional change, ok?

ok tb

> 
> 
> Index: uvm/uvm_pdaemon.c
> ===
> RCS file: /cvs/src/sys/uvm/uvm_pdaemon.c,v
> retrieving revision 1.107
> diff -u -p -r1.107 uvm_pdaemon.c
> --- uvm/uvm_pdaemon.c 16 Oct 2023 11:32:54 -  1.107
> +++ uvm/uvm_pdaemon.c 17 Oct 2023 10:28:25 -
> @@ -650,6 +650,11 @@ uvmpd_scan_inactive(struct uvm_pmalloc *
>   p->offset >> PAGE_SHIFT,
>   swslot + swcpages);
>   swcpages++;
> + rw_exit(slock);
> +
> + /* cluster not full yet? */
> + if (swcpages < swnpages)
> + continue;
>   }
>   } else {
>   /* if p == NULL we must be doing a last swap i/o */
> @@ -666,14 +671,6 @@ uvmpd_scan_inactive(struct uvm_pmalloc *
>* for object pages, we always do the pageout.
>*/
>   if (swap_backed) {
> - if (p) {/* if we just added a page to cluster */
> - rw_exit(slock);
> -
> - /* cluster not full yet? */
> - if (swcpages < swnpages)
> - continue;
> - }
> -
>   /* starting I/O now... set up for it */
>   npages = swcpages;
>   ppsp = swpps;
> 



small fix in uvmpd_scan_inactive()

2023-10-17 Thread Martin Pieuchot
Diff below merges two equivalent if blocks.  No functional change, ok?


Index: uvm/uvm_pdaemon.c
===
RCS file: /cvs/src/sys/uvm/uvm_pdaemon.c,v
retrieving revision 1.107
diff -u -p -r1.107 uvm_pdaemon.c
--- uvm/uvm_pdaemon.c   16 Oct 2023 11:32:54 -  1.107
+++ uvm/uvm_pdaemon.c   17 Oct 2023 10:28:25 -
@@ -650,6 +650,11 @@ uvmpd_scan_inactive(struct uvm_pmalloc *
p->offset >> PAGE_SHIFT,
swslot + swcpages);
swcpages++;
+   rw_exit(slock);
+
+   /* cluster not full yet? */
+   if (swcpages < swnpages)
+   continue;
}
} else {
/* if p == NULL we must be doing a last swap i/o */
@@ -666,14 +671,6 @@ uvmpd_scan_inactive(struct uvm_pmalloc *
 * for object pages, we always do the pageout.
 */
if (swap_backed) {
-   if (p) {/* if we just added a page to cluster */
-   rw_exit(slock);
-
-   /* cluster not full yet? */
-   if (swcpages < swnpages)
-   continue;
-   }
-
/* starting I/O now... set up for it */
npages = swcpages;
ppsp = swpps;



Re: nfsd: don't clear SB_NOINTR flag

2023-10-17 Thread Vitaliy Makkoveev
On Mon, Oct 16, 2023 at 10:17:50PM +0300, Vitaliy Makkoveev wrote:
> This socket comes from userland, so this flag is never set. This makes
> SB_NOINTR flag immutable, because we only set this bit on NFS client
> socket buffers for all it's lifetime.
> 
> I want to do this because this flag modifies sblock() behaviour and it's
> not clean which lock should protect it for standalone sblock().
> 
> ok?
> 
> I want to completely remove SB_NOINTR flag. Only NFS client sets it, but
> since the socket never passed to userland, this flag is useless, because
> we can't send singnal to kernel thread. So for this sblock()/sbwait()
> sleep is uninterruptible. But I want to not mix NFS server and NFS
> client diffs.
> 
> Index: sys/nfs/nfs_syscalls.c
> ===
> RCS file: /cvs/src/sys/nfs/nfs_syscalls.c,v
> retrieving revision 1.119
> diff -u -p -r1.119 nfs_syscalls.c
> --- sys/nfs/nfs_syscalls.c3 Aug 2023 09:49:09 -   1.119
> +++ sys/nfs/nfs_syscalls.c16 Oct 2023 19:00:02 -
> @@ -276,9 +276,7 @@ nfssvc_addsock(struct file *fp, struct m
>   m_freem(m);
>   }
>   solock(so);
> - so->so_rcv.sb_flags &= ~SB_NOINTR;
>   so->so_rcv.sb_timeo_nsecs = INFSLP;
> - so->so_snd.sb_flags &= ~SB_NOINTR;
>   so->so_snd.sb_timeo_nsecs = INFSLP;
>   sounlock(so);
>   if (tslp)
> 

To make the possible review easier, please look at sbin/nfsd/nfsd.c. We
have two cases, for UDP case we just pass newly created socket to kernel
side nfsd, for TCP case we pass only accepted sockets:

104 main(int argc, char *argv[])
105 {
/* ... */

208 if (udpflag) {
209 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
210 syslog(LOG_ERR, "can't create udp socket");
211 return (1);
212 }
/* ... */

228 nfsdargs.sock = sock;
229 nfsdargs.name = NULL;
230 nfsdargs.namelen = 0;
231 if (nfssvc(NFSSVC_ADDSOCK, ) == -1) {
232 syslog(LOG_ERR, "can't Add UDP socket");
233 return (1);
234 }
235 (void)close(sock);
236 }
/* ... */

241 if (tcpflag) {
242 if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
243 syslog(LOG_ERR, "can't create tcp socket");
244 return (1);
245 }
/* ... */

259 if (listen(tcpsock, 5) == -1) {
260 syslog(LOG_ERR, "listen failed");
261 return (1);
262 }
/* ... */

269 }
/* ... */

276 /*
277  * Loop forever accepting connections and passing the sockets
278  * into the kernel for the mounts.
279  */
280 for (;;) {
/* ... */

298 if (tcpflag) {
299 len = sizeof(inetpeer);
300 if ((msgsock = accept(tcpsock,
301 (struct sockaddr *), )) == -1) {
/* ... */

313 nfsdargs.sock = msgsock;
314 nfsdargs.name = (caddr_t)
315 nfsdargs.namelen = sizeof(inetpeer);
316 if (nfssvc(NFSSVC_ADDSOCK, ) == -1) {
317 syslog(LOG_ERR, "can't Add TCP socket");
318 return (1);
319 }
320 (void)close(msgsock);
321 }
322 }

For the NFSSVC_ADDSOCK command, sys_nfssvc() gets associated descriptor
and passes it to nfssvc_addsock().

141 sys_nfssvc(struct proc *p, void *v, register_t *retval)
142 {
/* ... */

171 switch (flags) {
172 case NFSSVC_ADDSOCK:
173 error = copyin(SCARG(uap, argp), , sizeof(nfsdarg));
174 if (error)
175 return (error);
176 
177 error = getsock(p, nfsdarg.sock, );
/* ... */

194 error = nfssvc_addsock(fp, nam);


nfssvc_addsock() gets associated socket, does necessary setup and passes
it to nfsd. There is the only place where we clean this flag.

225 nfssvc_addsock(struct file *fp, struct mbuf *mynam)
226 {
/* ... */

278 solock(so);
279 so->so_rcv.sb_flags &= ~SB_NOINTR;
280 so->so_rcv.sb_timeo_nsecs = INFSLP;
281 so->so_snd.sb_flags &= ~SB_NOINTR;
282 so->so_snd.sb_timeo_nsecs = INFSLP;
283 sounlock(so);

The only place where we set this flag is the NFS client related socket.
It always created in kernel space and it never comes to the userland.
This socket can't be passed to nfsd.

234 nfs_connect(struct nfsmount *nmp, struct nfsreq *rep)
235 {
/* ... */

247 error = socreate(saddr->sa_family, >nm_so, 

Re: Improve IPv6 link-local support in bgpd

2023-10-17 Thread Sebastian Benoit
Claudio Jeker(cje...@diehard.n-r-g.com) on 2023.10.16 09:23:12 +0200:
> This diff fixes a few more things when establishing connections with
> link-local IPv6 addresses. In get_alternate_addr() the interface scope
> of the connection is recovered and then passed to the RDE. The RDE can
> then use this scope id to insert link-local addresses with the correct
> scope.

looks good.
 
> I built a regress test for this which passes with this diff.
> Now probably more is needed because IPv6 link-local addresses are a gift
> that keep on giving. One thing to implement on top of this is template
> matching for link local -- which allows to auto-configure sessions more
> easily. This will probably follow soon.

it would be nice if that could match just on interfaces. As in "neighbor
", with some syntactic sugar so its clear this is for
link-local?

 
> -- 
> :wq Claudio
> 
> Index: bgpd.h
> ===
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.477
> diff -u -p -r1.477 bgpd.h
> --- bgpd.h30 Aug 2023 08:16:28 -  1.477
> +++ bgpd.h9 Oct 2023 13:50:36 -
> @@ -796,6 +796,7 @@ struct session_up {
>   struct bgpd_addrremote_addr;
>   struct capabilities capa;
>   uint32_tremote_bgpid;
> + unsigned intif_scope;
>   uint16_tshort_as;
>  };
>  
> @@ -1439,6 +1440,7 @@ void kr_ifinfo(char *);
>  void  kr_net_reload(u_int, uint64_t, struct network_head *);
>  int   kr_reload(void);
>  int   get_mpe_config(const char *, u_int *, u_int *);
> +uint8_t   mask2prefixlen(sa_family_t, struct sockaddr *);
>  
>  /* log.c */
>  void  log_peer_info(const struct peer_config *, const char *, ...)
> Index: kroute.c
> ===
> RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
> retrieving revision 1.305
> diff -u -p -r1.305 kroute.c
> --- kroute.c  1 Jun 2023 09:47:34 -   1.305
> +++ kroute.c  9 Oct 2023 13:54:25 -
> @@ -168,8 +168,6 @@ struct kroute6*kroute6_match(struct kta
>  void  kroute_detach_nexthop(struct ktable *, struct knexthop *);
>  
>  uint8_t  prefixlen_classful(in_addr_t);
> -uint8_t  mask2prefixlen(in_addr_t);
> -uint8_t  mask2prefixlen6(struct sockaddr_in6 *);
>  uint64_t ift2ifm(uint8_t);
>  const char   *get_media_descr(uint64_t);
>  const char   *get_linkstate(uint8_t, int);
> @@ -2419,21 +2417,28 @@ prefixlen_classful(in_addr_t ina)
>   return (8);
>  }
>  
> -uint8_t
> -mask2prefixlen(in_addr_t ina)
> +static uint8_t
> +mask2prefixlen4(struct sockaddr_in *sa_in)
>  {
> + in_addr_t ina;
> +
> + if (sa_in->sin_len == 0)
> + return (0);
> + ina = sa_in->sin_addr.s_addr;
>   if (ina == 0)
>   return (0);
>   else
>   return (33 - ffs(ntohl(ina)));
>  }
>  
> -uint8_t
> +static uint8_t
>  mask2prefixlen6(struct sockaddr_in6 *sa_in6)
>  {
>   uint8_t *ap, *ep;
>   u_intl = 0;
>  
> + if (sa_in6->sin6_len == 0)
> + return (0);
>   /*
>* sin6_len is the size of the sockaddr so subtract the offset of
>* the possibly truncated sin6_addr struct.
> @@ -2480,6 +2485,19 @@ mask2prefixlen6(struct sockaddr_in6 *sa_
>   return (l);
>  }
>  
> +uint8_t
> +mask2prefixlen(sa_family_t af, struct sockaddr *mask)
> +{
> + switch (af) {
> + case AF_INET:
> + return mask2prefixlen4((struct sockaddr_in *)mask);
> + case AF_INET6:
> + return mask2prefixlen6((struct sockaddr_in6 *)mask);
> + default:
> + fatalx("%s: unsupported af", __func__);
> + }
> +}
> +
>  const struct if_status_description
>   if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
>  const struct ifmedia_description
> @@ -3079,9 +3097,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt
>   case AF_INET:
>   sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
>   if (sa_in != NULL) {
> - if (sa_in->sin_len != 0)
> - kf->prefixlen =
> - mask2prefixlen(sa_in->sin_addr.s_addr);
> + kf->prefixlen = mask2prefixlen4(sa_in);
>   } else if (rtm->rtm_flags & RTF_HOST)
>   kf->prefixlen = 32;
>   else
> @@ -3091,8 +3107,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt
>   case AF_INET6:
>   sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
>   if (sa_in6 != NULL) {
> - if (sa_in6->sin6_len != 0)
> - kf->prefixlen = mask2prefixlen6(sa_in6);
> + kf->prefixlen = mask2prefixlen6(sa_in6);
>   } else if (rtm->rtm_flags & RTF_HOST)
>   kf->prefixlen = 128;
>

Re: log.c use buffered IO

2023-10-17 Thread Sebastian Benoit
Theo Buehler(t...@theobuehler.org) on 2023.10.17 09:13:15 +0200:
> On Mon, Oct 16, 2023 at 12:19:17PM +0200, Claudio Jeker wrote:
> > I dislike how log.c does all these asprintf() calls with dubious
> > workaround calls in case asprintf() fails.
> 
> You're not alone.
> 
> > IMO it is easier to use the stdio provided buffers and fflush() to get
> > "atomic" writes on stderr. At least from my understanding this is the
> > reason to go all this lenght to do a single fprintf call.
> 
> This makes sense, but I don't know the history here.

as far as i can remember, it was done so it would still be able to work
somewhat when out of memeory.
 
> > We need this since in privsep daemons can log from multiple processes
> > concurrently and we want the log to be not too mangled.
> > 
> > While there also use one static buffer to handle log_warn() and vfatalc()
> > where the error message is first expanded and then printed with
> > logit(LOG_ERR, "%s: %s", fmtbuf, strerror(saved_errno));
> > 
> > Any opinions?
> 
> I like this much better than the existing code.
> 
> ok tb, one small request inline
> 
> > -- 
> > :wq Claudio
> > 
> > Index: log.c
> > ===
> > RCS file: /cvs/src/usr.sbin/bgpd/log.c,v
> > retrieving revision 1.64
> > diff -u -p -r1.64 log.c
> > --- log.c   21 Mar 2017 12:06:55 -  1.64
> > +++ log.c   16 Oct 2023 09:42:55 -
> > @@ -29,6 +29,7 @@
> >  static int  debug;
> >  static int  verbose;
> >  static const char  *log_procname;
> > +static char logbuf[4096], fmtbuf[4096];
> >  
> >  void
> >  log_init(int n_debug, int facility)
> > @@ -41,6 +42,8 @@ log_init(int n_debug, int facility)
> >  
> > if (!debug)
> > openlog(__progname, LOG_PID | LOG_NDELAY, facility);
> > +   else
> > +   setvbuf(stderr, logbuf, _IOFBF, sizeof(logbuf));

can you turn this around (if (debug) ...)

> > tzset();
> >  }
> > @@ -77,18 +80,11 @@ logit(int pri, const char *fmt, ...)
> >  void
> >  vlog(int pri, const char *fmt, va_list ap)
> >  {
> > -   char*nfmt;
> > int  saved_errno = errno;
> >  
> > if (debug) {
> 
> Could log_init() and vlog() either both use if (debug) or both if (!debug),
> please? Missing the ! in log_init() confused me for a few minutes since it
> looked wrong.

yes please :)

> 
> > -   /* best effort in out of mem situations */
> > -   if (asprintf(, "%s\n", fmt) == -1) {
> > -   vfprintf(stderr, fmt, ap);
> > -   fprintf(stderr, "\n");
> > -   } else {
> > -   vfprintf(stderr, nfmt, ap);
> > -   free(nfmt);
> > -   }
> > +   vfprintf(stderr, fmt, ap);
> > +   fprintf(stderr, "\n");
> > fflush(stderr);
> > } else
> > vsyslog(pri, fmt, ap);
> > @@ -99,7 +95,6 @@ vlog(int pri, const char *fmt, va_list a
> >  void
> >  log_warn(const char *emsg, ...)
> >  {
> > -   char*nfmt;
> > va_list  ap;
> > int  saved_errno = errno;
> >  
> > @@ -108,16 +103,8 @@ log_warn(const char *emsg, ...)
> > logit(LOG_ERR, "%s", strerror(saved_errno));
> > else {
> > va_start(ap, emsg);
> > -
> > -   if (asprintf(, "%s: %s", emsg,
> > -   strerror(saved_errno)) == -1) {
> > -   /* we tried it... */
> > -   vlog(LOG_ERR, emsg, ap);
> > -   logit(LOG_ERR, "%s", strerror(saved_errno));
> > -   } else {
> > -   vlog(LOG_ERR, nfmt, ap);
> > -   free(nfmt);
> > -   }
> > +   (void)vsnprintf(fmtbuf, sizeof(fmtbuf), emsg, ap);
> > +   logit(LOG_ERR, "%s: %s", fmtbuf, strerror(saved_errno));
> > va_end(ap);
> > }
> >  
> > @@ -159,21 +146,20 @@ log_debug(const char *emsg, ...)
> >  static void
> >  vfatalc(int code, const char *emsg, va_list ap)
> >  {
> > -   static char s[BUFSIZ];
> > const char  *sep;
> >  
> > if (emsg != NULL) {
> > -   (void)vsnprintf(s, sizeof(s), emsg, ap);
> > +   (void)vsnprintf(fmtbuf, sizeof(fmtbuf), emsg, ap);
> > sep = ": ";
> > } else {
> > -   s[0] = '\0';
> > +   fmtbuf[0] = '\0';
> > sep = "";
> > }
> > if (code)
> > logit(LOG_CRIT, "fatal in %s: %s%s%s",
> > -   log_procname, s, sep, strerror(code));
> > +   log_procname, fmtbuf, sep, strerror(code));
> > else
> > -   logit(LOG_CRIT, "fatal in %s%s%s", log_procname, sep, s);
> > +   logit(LOG_CRIT, "fatal in %s%s%s", log_procname, sep, fmtbuf);
> >  }
> >  
> >  void
> > 
> 



Re: log.c use buffered IO

2023-10-17 Thread Theo Buehler
On Mon, Oct 16, 2023 at 12:19:17PM +0200, Claudio Jeker wrote:
> I dislike how log.c does all these asprintf() calls with dubious
> workaround calls in case asprintf() fails.

You're not alone.

> IMO it is easier to use the stdio provided buffers and fflush() to get
> "atomic" writes on stderr. At least from my understanding this is the
> reason to go all this lenght to do a single fprintf call.

This makes sense, but I don't know the history here.

> We need this since in privsep daemons can log from multiple processes
> concurrently and we want the log to be not too mangled.
> 
> While there also use one static buffer to handle log_warn() and vfatalc()
> where the error message is first expanded and then printed with
> logit(LOG_ERR, "%s: %s", fmtbuf, strerror(saved_errno));
> 
> Any opinions?

I like this much better than the existing code.

ok tb, one small request inline

> -- 
> :wq Claudio
> 
> Index: log.c
> ===
> RCS file: /cvs/src/usr.sbin/bgpd/log.c,v
> retrieving revision 1.64
> diff -u -p -r1.64 log.c
> --- log.c 21 Mar 2017 12:06:55 -  1.64
> +++ log.c 16 Oct 2023 09:42:55 -
> @@ -29,6 +29,7 @@
>  static intdebug;
>  static intverbose;
>  static const char*log_procname;
> +static char   logbuf[4096], fmtbuf[4096];
>  
>  void
>  log_init(int n_debug, int facility)
> @@ -41,6 +42,8 @@ log_init(int n_debug, int facility)
>  
>   if (!debug)
>   openlog(__progname, LOG_PID | LOG_NDELAY, facility);
> + else
> + setvbuf(stderr, logbuf, _IOFBF, sizeof(logbuf));
>  
>   tzset();
>  }
> @@ -77,18 +80,11 @@ logit(int pri, const char *fmt, ...)
>  void
>  vlog(int pri, const char *fmt, va_list ap)
>  {
> - char*nfmt;
>   int  saved_errno = errno;
>  
>   if (debug) {

Could log_init() and vlog() either both use if (debug) or both if (!debug),
please? Missing the ! in log_init() confused me for a few minutes since it
looked wrong.

> - /* best effort in out of mem situations */
> - if (asprintf(, "%s\n", fmt) == -1) {
> - vfprintf(stderr, fmt, ap);
> - fprintf(stderr, "\n");
> - } else {
> - vfprintf(stderr, nfmt, ap);
> - free(nfmt);
> - }
> + vfprintf(stderr, fmt, ap);
> + fprintf(stderr, "\n");
>   fflush(stderr);
>   } else
>   vsyslog(pri, fmt, ap);
> @@ -99,7 +95,6 @@ vlog(int pri, const char *fmt, va_list a
>  void
>  log_warn(const char *emsg, ...)
>  {
> - char*nfmt;
>   va_list  ap;
>   int  saved_errno = errno;
>  
> @@ -108,16 +103,8 @@ log_warn(const char *emsg, ...)
>   logit(LOG_ERR, "%s", strerror(saved_errno));
>   else {
>   va_start(ap, emsg);
> -
> - if (asprintf(, "%s: %s", emsg,
> - strerror(saved_errno)) == -1) {
> - /* we tried it... */
> - vlog(LOG_ERR, emsg, ap);
> - logit(LOG_ERR, "%s", strerror(saved_errno));
> - } else {
> - vlog(LOG_ERR, nfmt, ap);
> - free(nfmt);
> - }
> + (void)vsnprintf(fmtbuf, sizeof(fmtbuf), emsg, ap);
> + logit(LOG_ERR, "%s: %s", fmtbuf, strerror(saved_errno));
>   va_end(ap);
>   }
>  
> @@ -159,21 +146,20 @@ log_debug(const char *emsg, ...)
>  static void
>  vfatalc(int code, const char *emsg, va_list ap)
>  {
> - static char s[BUFSIZ];
>   const char  *sep;
>  
>   if (emsg != NULL) {
> - (void)vsnprintf(s, sizeof(s), emsg, ap);
> + (void)vsnprintf(fmtbuf, sizeof(fmtbuf), emsg, ap);
>   sep = ": ";
>   } else {
> - s[0] = '\0';
> + fmtbuf[0] = '\0';
>   sep = "";
>   }
>   if (code)
>   logit(LOG_CRIT, "fatal in %s: %s%s%s",
> - log_procname, s, sep, strerror(code));
> + log_procname, fmtbuf, sep, strerror(code));
>   else
> - logit(LOG_CRIT, "fatal in %s%s%s", log_procname, sep, s);
> + logit(LOG_CRIT, "fatal in %s%s%s", log_procname, sep, fmtbuf);
>  }
>  
>  void
>