Re: POSIX-compliant page fault error codes
Matthew -- fine, you collected information. Thank you. It is quite clear that POSIX set in stone an accident, a significant error in my opinion. Anyone with enough expertise can recognize this is an accident in the SVR4 codebase, which ended up being "ratified" (in quotes, because the more mistakes you make, the less value there is). This specific refinement may help a few pieces of code which require specific detail in siginfo, but it introduces a lot more accidental risk in those which only use the signal number/handler. It is complicated enough that it requires experts to review how (typically poorly) programs (written by non-experts) use signals to deal with this added kernel behaviour. As in, it is bad enough that I am scared even for the way that SIGBUS and SIGSEGV handlers in crap programs in base handle it. The issue of unsafe terminal signal handlers returns IN FORCE, and we need to cope with those. Nothing ever changes, noone ever learns, noone cares. Where we go from continues to be a big question mark. Compatible? one issue.. not compatible? another issue.. Thanks POSIX, whoever you are. What favors did you do us recently?
Re: POSIX-compliant page fault error codes
On Tue, Jun 24, 2014 at 11:04:10AM -0700, Matthew Dempsky wrote: > SIGBUS/BUS_ADRERR: Accessing a mapped page that exceeds the end of > the underlying mapped file. Generating SIGBUS for this case has proven controversial due to concern that this is Linux invented behavior and not compatible with Solaris, so I decided to collect some more background information on the subject. - SunOS 4.1.3's mmap() manual specifies: "Any reference to addresses beyond the end of the object, however, will result in the delivery of a SIGBUS signal." This wording was relaxed to "SIGBUS or SIGSEGV" in SunOS 5.6 and remains in current manuals. (I'm not sure, but I suspect this may be to simply reflect that memory protection violations take priority over bounds checking.) SunOS 4.1.3: http://www.freebsd.org/cgi/man.cgi?query=mmap&sektion=2&manpath=SunOS+4.1.3 SunOS 5.6: http://www.freebsd.org/cgi/man.cgi?query=mmap&sektion=2&manpath=SunOS+5.6 Solaris 11: http://docs.oracle.com/cd/E23824_01/html/821-1463/mmap-2.html - Many other SVR-derived OSes similarly document SIGBUS in their mmap() manuals too: AIX: http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.basetechref/doc/basetrf1/mmap.htm?lang=en HPUX: http://h20566.www2.hp.com/portal/site/hpsc/template.BINARYPORTLET/public/kb/docDisplay/resource.process/?spf_p.tpst=kbDocDisplay_ws_BI&spf_p.rid_kbDocDisplay=docDisplayResURL&javax.portlet.begCacheTok=com.vignette.cachetoken&spf_p.rst_kbDocDisplay=wsrp-resourceState%3DdocId%253Demr_na-c02261243-2%257CdocLocale%253D&javax.portlet.endCacheTok=com.vignette.cachetoken UnixWare: http://uw714doc.sco.com/en/man/html.2/mmap.2.html - This behavior has been (awkwardly) specified for mmap() since SUSv2: "References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal." Later versions of POSIX have the same wording. SUSv2: http://pubs.opengroup.org/onlinepubs/007908799/xsh/mmap.html POSIX.2001: http://pubs.opengroup.org/onlinepubs/009695399/functions/mmap.html POSIX.2008: http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html - More generally, POSIX explains the SIGBUS/SIGSEGV distinction thusly: "When an object is mapped, various application accesses to the mapped region may result in signals. In this context, SIGBUS is used to indicate an error using the mapped object, and SIGSEGV is used to indicate a protection violation or misuse of an address." Specific examples are provided too: Memory Protection: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_08_03_03
Re: audio(9) manual page
* Jason McIntyre [140625 00:41]: > On Tue, Jun 24, 2014 at 09:13:47AM +0200, Alexandre Ratchov wrote: > > I see what you mean. As the manual describes the interface between > > two layers we may need to be more precise about who calls who. > > Wouldn't the following be less ambigous? > > > > When the hardware is ready to accept more samples the driver shall > > call the > > .Fa intr > > function with the argument > > .Fa intrarg . > > > > the use of "will" is perfectly fine here - it's basically a conditional > sentence structure. > > "shall" sounds awful. it sounds formal, dated, and like a document > produced by posix. please don;t make this change. > > what is simpler, i think, and easier for most folks to understand, is > using a present tense: > > When the hardware is ready to accept more samples, > the driver calls the > .Fa intr > function with the argument > .Fa intrarg . > > it's all a matter of taste, i suppose, but present tense structure does > seem to be easier to read for non-native speakers (in my experience). I agree, this one looks even better.
newfs_msdos: proper boot signature
Hi, time to merge another fix from NetBSD (and FreeBSD who applied it too): If sector size is not 512, the boot signature is placed at a wrong position. It always has to be at offset 510/511, not sector size - 2. # dd if=/dev/zero of=fat.iso bs=1M count=1 # vnconfig vnd0c fat.iso # newfs_msdos -S 4096 vnd0c /dev/rvnd0c: 2041 sectors in 2041 FAT12 clusters (4096 bytes/cluster) bps=4096 spc=1 res=1 nft=2 rde=512 sec=2048 mid=0xf0 spf=1 spt=63 hds=1 hid=0 # fsck_msdos vnd0c ** /dev/rvnd0c (vnd0c) Invalid signature in boot block: Also, the minimum allowed sector size is 512. NetBSD (Revision 1.24): Don't use negative offsets from "bpb.bps" when writing out values such as DOSMAGIC in the MBR. In non-512 byte media, the MBR is still 512 bytes in length. Based on the patches provided in PR kern/17398 by Trevin Beattie. FreeBSD (Revision 170166): The newfs_msdos utility does not store the boot signature in the correct place on large sector disks. The boot signature should be at offset 0x1fe in the BPB; newfs_msdos currently stores it 2 bytes from the end of the sector. Taken from: NetBSD Tobias Index: newfs_msdos.8 === RCS file: /cvs/src/sbin/newfs_msdos/newfs_msdos.8,v retrieving revision 1.24 diff -u -p -r1.24 newfs_msdos.8 --- newfs_msdos.8 16 Jul 2013 09:45:28 - 1.24 +++ newfs_msdos.8 24 Jun 2014 19:20:35 - @@ -134,7 +134,7 @@ Number of hidden sectors. Number of reserved sectors. .It Fl S Ar sector-size Number of bytes per sector. -Acceptable values are powers of 2 in the range 128 through 32768. +Acceptable values are powers of 2 in the range 512 through 32768. .It Fl s Ar total File system size. .It Fl u Ar track-size Index: newfs_msdos.c === RCS file: /cvs/src/sbin/newfs_msdos/newfs_msdos.c,v retrieving revision 1.22 diff -u -p -r1.22 newfs_msdos.c --- newfs_msdos.c 22 Nov 2013 04:14:01 - 1.22 +++ newfs_msdos.c 24 Jun 2014 19:20:35 - @@ -50,7 +50,7 @@ #define NPB 2 /* nibbles per byte */ #define DOSMAGIC 0xaa55 /* DOS magic number */ -#define MINBPS 128 /* minimum bytes per sector */ +#define MINBPS 512 /* minimum bytes per sector */ #define MAXSPC 128 /* maximum sectors per cluster */ #define MAXNFT 16/* maximum number of FATs */ #define DEFBLK 4096 /* default block size */ @@ -617,17 +617,17 @@ main(int argc, char *argv[]) setstr(bs->oem, opt_O ? opt_O : "BSD 4.4", sizeof(bs->oem)); memcpy(img + x1, bootcode, sizeof(bootcode)); - mk2(img + bpb.bps - 2, DOSMAGIC); + mk2(img + MINBPS - 2, DOSMAGIC); } } else if (fat == 32 && bpb.infs != MAXU16 && (lsn == bpb.infs || (bpb.bkbs != MAXU16 && lsn == bpb.bkbs + bpb.infs))) { mk4(img, 0x41615252); - mk4(img + bpb.bps - 28, 0x61417272); - mk4(img + bpb.bps - 24, 0x); - mk4(img + bpb.bps - 20, bpb.rdcl); - mk2(img + bpb.bps - 2, DOSMAGIC); + mk4(img + MINBPS - 28, 0x61417272); + mk4(img + MINBPS - 24, 0x); + mk4(img + MINBPS - 20, bpb.rdcl); + mk2(img + MINBPS - 2, DOSMAGIC); } else if (lsn >= bpb.res && lsn < dir && !((lsn - bpb.res) % (bpb.spf ? bpb.spf : bpb.bspf))) {
POSIX-compliant page fault error codes
POSIX specifies these error cases for memory faults: SIGSEGV/SEGV_MAPERR: Accessing an unmapped page. SIGSEGV/SEGV_ACCERR: Reading from a non-readable or writing to a non-writable page. SIGBUS/BUS_ADRERR: Accessing a mapped page that exceeds the end of the underlying mapped file. I added a regress test at regress/sys/kern/siginfo-fault to cover these cases, but unfortunately we're non-compliant in a few ways, and fixing it is somewhat MD. With the diff below, the tests pass on amd64, but other platforms will need similar changes. Currently VM_PAGER_BAD is only returned by pgo_get() in the case of uvn_get() trying to access a page beyond the end of the file, so this diff changes uvm_fault() to recognize this and return ENOSPC (arbitrary unused error code) and then the MD trap() code needs to know to map this error to BUS_ADRERR. Additionally, some MD trap()s already know to map EACCES to SEGV_ACCERR instead of SEGV_MAPERR, but amd64 wasn't one of them. So this diff fixes that too. Index: uvm/uvm_fault.c === RCS file: /home/matthew/cvs-mirror/cvs/src/sys/uvm/uvm_fault.c,v retrieving revision 1.73 diff -u -p -r1.73 uvm_fault.c --- uvm/uvm_fault.c 8 May 2014 20:08:50 - 1.73 +++ uvm/uvm_fault.c 23 Jun 2014 21:29:24 - @@ -1125,7 +1125,8 @@ Case2: goto ReFault; } - return (EACCES); /* XXX i/o error */ + /* XXX i/o error */ + return (result == VM_PAGER_BAD ? ENOSPC : EACCES); } /* re-verify the state of the world. */ Index: arch/amd64/amd64/trap.c === RCS file: /home/matthew/cvs-mirror/cvs/src/sys/arch/amd64/amd64/trap.c,v retrieving revision 1.40 diff -u -p -r1.40 trap.c --- arch/amd64/amd64/trap.c 15 Jun 2014 11:43:24 - 1.40 +++ arch/amd64/amd64/trap.c 23 Jun 2014 21:38:31 - @@ -387,9 +387,6 @@ faultcommon: KERNEL_UNLOCK(); goto out; } - if (error == EACCES) { - error = EFAULT; - } if (type == T_PAGEFLT) { if (pcb->pcb_onfault != 0) { @@ -407,13 +404,23 @@ faultcommon: sv.sival_ptr = (void *)fa; trapsignal(p, SIGKILL, T_PAGEFLT, SEGV_MAPERR, sv); } else { + int signo, code; + if (error == ENOSPC) { + signo = SIGBUS; + code = BUS_ADRERR; + } else { + signo = SIGSEGV; + code = (error == EACCES) ? SEGV_ACCERR : + SEGV_MAPERR; + } #ifdef TRAP_SIGDEBUG - printf("pid %d (%s): SEGV at rip %lx addr %lx\n", - p->p_pid, p->p_comm, frame->tf_rip, fa); + printf("pid %d (%s): %s at rip %lx addr %lx\n", + p->p_pid, p->p_comm, (signo == SIGBUS) ? + "BUS" : "SEGV", frame->tf_rip, fa); frame_dump(frame); #endif sv.sival_ptr = (void *)fa; - trapsignal(p, SIGSEGV, T_PAGEFLT, SEGV_MAPERR, sv); + trapsignal(p, signo, T_PAGEFLT, code, sv); } KERNEL_UNLOCK(); break;
Re: PATCH: ftp: allow @ in username for Basic Auth
On Tue, Jun 24, 2014 at 9:01 AM, Sébastien Marie < semarie-open...@latrappe.fr> wrote: > As I see not activity or feedback for this one line patch, I think it > need more explain ? > Sorry, the patch is incorrect; per RFC 3986, the parser is correct to split the authority on the first '@'. The correct method to include an '@' in the userinfo part is to percent-encode it as %40. Philip Guenther
Re: Undefined symbol in ld.so
Whoops! Sorry for the confusion; disregard. On Jun 24, 2014, at 3:31 AM, Otto Moerbeek wrote: > On Tue, Jun 24, 2014 at 01:30:55AM -0700, William Orr wrote: > >> ld.so in -current isn't building right now, due to an undefined reference to >> _dl_realloc caused by the recent addition of _dl_reallocarray. The following >> diff implements _dl_realloc, largely copied from the implementation in >> lib/libc/stdlib/malloc.c. > > There are cvssync problems. The code in curent compiles fine. > > -Otto > >> >> tested on amd64 >> >> Index: malloc.c >> === >> RCS file: /cvs/src/libexec/ld.so/malloc.c,v >> retrieving revision 1.1 >> diff -u -b -w -p -r1.1 malloc.c >> --- malloc.c 5 Jun 2014 08:39:07 - 1.1 >> +++ malloc.c 24 Jun 2014 08:24:43 - >> @@ -78,6 +78,12 @@ >> #define MMAP(sz) _dl_mmap(NULL, (size_t)(sz), PROT_READ | PROT_WRITE, \ >> MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) >> >> +#define MMAPA(a,sz) _dl_mmap((a), (size_t)(sz), PROT_READ | PROT_WRITE, \ >> +MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) >> + >> +#define MQUERY(a, sz) _dl_mquery((a), (size_t)(sz), PROT_READ | >> PROT_WRITE, \ >> +MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, (off_t)0) >> + >> #define MMAP_ERROR(p)(_dl_mmap_error(p) ? MAP_FAILED : (p)) >> >> struct region_info { >> @@ -277,6 +283,26 @@ unmap(struct dir_info *d, void *p, size_ >> wrterror("malloc cache overflow"); >> } >> >> +static void >> +zapcacheregion(struct dir_info *d, void *p, size_t len) >> +{ >> +u_int i; >> +struct region_info *r; >> +size_t rsz; >> + >> +for (i = 0; i < mopts.malloc_cache; i++) { >> +r = &d->free_regions[i]; >> +if (r->p >= p && r->p <= (void *)((char *)p + len)) { >> +rsz = r->size << MALLOC_PAGESHIFT; >> +if (_dl_munmap(r->p, rsz)) >> +wrterror("munmap"); >> +r->p = NULL; >> +d->free_regions_size -= r->size; >> +r->size = 0; >> +} >> +} >> +} >> + >> static void * >> map(struct dir_info *d, size_t sz, int zero_fill) >> { >> @@ -987,6 +1013,119 @@ _dl_free(void *ptr) >> malloc_active--; >> } >> >> +static void * >> +orealloc(void *p, size_t newsz) >> +{ >> +struct region_info *r; >> +size_t oldsz, goldsz, gnewsz; >> +void *q; >> + >> +if (p == NULL) >> +return omalloc(newsz, 0); >> + >> +r = find(g_pool, p); >> +if (r == NULL) { >> +wrterror("bogus pointer (double free?)"); >> +return NULL; >> +} >> +if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) >> +return NULL; >> + >> +REALSIZE(oldsz, r); >> +goldsz = oldsz; >> +if (oldsz > MALLOC_MAXCHUNK) { >> +if (oldsz < mopts.malloc_guard) >> +wrterror("guard size"); >> +oldsz -= mopts.malloc_guard; >> +} >> + >> +gnewsz = newsz; >> +if (gnewsz > MALLOC_MAXCHUNK) >> +gnewsz += mopts.malloc_guard; >> + >> +if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p) { >> +size_t roldsz = PAGEROUND(goldsz); >> +size_t rnewsz = PAGEROUND(gnewsz); >> + >> +if (rnewsz > roldsz) { >> +if (!mopts.malloc_guard) { >> +void *hint = (char *)p + roldsz; >> +size_t needed = rnewsz - roldsz; >> + >> +zapcacheregion(g_pool, hint, needed); >> +q = MQUERY(hint, needed); >> +if (q == hint) >> +q = MMAPA(hint, needed); >> +else >> +q = MAP_FAILED; >> +if (q == hint) { >> +if (mopts.malloc_junk == 2) >> +_dl_memset(q, SOME_JUNK, >> needed); >> +r->size = newsz; >> +return p; >> +} else if (q != MAP_FAILED) { >> +if (_dl_munmap(q, needed)) >> +wrterror("munmap"); >> +} >> +} >> +} else if (rnewsz < roldsz) { >> +if (mopts.malloc_guard) { >> +if (_dl_mprotect((char *)p + roldsz - >> +mopts.malloc_guard, mopts.malloc_guard, >> +PROT_READ | PROT_WRITE)) >> +wrterror("mprotect"); >> +if (_dl_mprotect((char *)p + rnewsz - >> +mopts.malloc_guard, mopts.malloc_guard, >> +PROT_NO
Re: PATCH: ftp: allow @ in username for Basic Auth
Hi, As I see not activity or feedback for this one line patch, I think it need more explain ? Currently, when you pass an URL with user/pass embed, the code parse it badly. For example: https://mym...@example.com:my-passw...@another-domain.example.com/blabla Just before the code search if the supplied URL contains a user/pass, the variables are: scheme = "https://"; host = "mym...@example.com:my-passw...@another-domain.example.com" The code use strchr(3) on host in order to find '@' in host variable, and separate the user/pass component and the host component. But, with strchr the result is: p = "mymail" host = "example.com:my-passw...@another-domain.example.com" The patch replace strchr(3) by strrchr(3) to obtain: p = "mym...@example.com:my-password" host = "another-domain.example.com" As the hostname should not contains '@' char, and user/pass may contains it, (as defined by rfc1738), this patch make ftp(1) to more respect standard. Thanks. -- Sébastien Marie On Mon, Jun 23, 2014 at 10:15:25AM +0200, Sébastien Marie wrote: > Hi, > > Using ftp(1) with HTTP(S) scheme and Basic auth, it is currently not > possible to have username (or password) with a '@' inner. > > For example, this URI is badly parsed: > ftp https://mym...@example.com:my-passw...@another-domain.example.com/blabla > > According to RFC2617, '@' is a valid character in user-id or password: > user-pass = userid ":" password > userid = * > password= *TEXT > > Here a patch to search the last '@' in the string (which don't contains > the path at this time). > > -- > Sébastien Marie > > Index: fetch.c > === > RCS file: /cvs/src/usr.bin/ftp/fetch.c,v > retrieving revision 1.122 > diff -u -p -r1.122 fetch.c > --- fetch.c 20 May 2014 01:25:23 - 1.122 > +++ fetch.c 23 Jun 2014 07:46:33 - > @@ -474,7 +474,7 @@ noslash: >*/ > if (proxyenv == NULL && > (!strcmp(scheme, HTTP_URL) || !strcmp(scheme, HTTPS_URL))) { > - if ((p = strchr(host, '@')) != NULL) { > + if ((p = strrchr(host, '@')) != NULL) { > size_t authlen = (strlen(host) + 5) * 4 / 3; > *p = 0; /* Kill @ */ > if ((auth = malloc(authlen)) == NULL) >
Re: infnan.3
Hi, Theo de Raadt wrote on Tue, Jun 24, 2014 at 09:09:49AM -0600: > Ingo Schwarze wrote: >> It's obvious that whole page needs a content update by a VAX expert. > that is correct. All the rest of the discussion is moot. > > Only miod and martynas can swing this the right way. > > I disagree with Ted about making this a seperate page, As i said before, infnan(3/vax) already *is* a separate, architecture-specific, VAX-only page. It is cross-referenced from various machine independent pages, though. I cannot miss the opportunity to show this off: ischwarze@isnote $ apropos Xr=infnan atanh, atanhf, atanhl(3) - inverse hyperbolic tangent functions gamma, gammaf, lgamma, lgammaf, lgammal, tgamma, tgammaf, tgammal(3) - log gamma functions exp, exp2, exp2f, exp2l, expf, expl, expm1, expm1f, expm1l, log, log10, log10f, log10l, log1p, log1pf, log1pl, log2, log2f, log2l, logf, logl, pow, powf, powl(3) - exponential, logarithm, power functions asinh, asinhf, asinhl(3) - inverse hyperbolic sine functions acosh, acoshf, acoshl(3) - inverse hyperbolic cosine functions Yours, Ingo > since that would remove a vital component of floating point > knowledge from programmers, that being: not all floating point > is the same, not all of it is ieee, and not even ieee implementaiton > is consistant. Some visibility must remain to show that there is > sausage being made here.
Re: infnan.3
> It's obvious that whole page needs a content update by a VAX expert. that is correct. All the rest of the discussion is moot. Only miod and martynas can swing this the right way. I disagree with Ted about making this a seperate page, since that would remove a vital component of floating point knowledge from programmers, that being: not all floating point is the same, not all of it is ieee, and not even ieee implementaiton is consistant. Some visibility must remain to show that there is sausage being made here.
Re: pfctl: stricter redirect specs
On 2014/06/24 15:07, Mike Belopuhov wrote: > I propose to avoid the confusion by flagging such situations as > errors, e.g.: > > % echo 'pass out nat-to { ::1 1.1.1.1 }' | ./obj/pfctl -o none -vnf - > stdin:1: translation spec contains addresses with different address families > stdin:1: skipping rule due to errors > stdin:1: rule expands to no valid combination > > While previously it would pick only one of them (the first one): I agree with this change, it does need a warning in current.html to avoid users being bitten by it (mostly this is likely when using interface names e.g. "echo 'pass out nat-to lo0' | pfctl -vnf -"), however the recent change to disabling ipv6 by default should reduce the impact of this.
Re: pfctl: stricter redirect specs
On Tue, Jun 24, 2014 at 15:07 +0200, Mike Belopuhov wrote: > I have carefully tested that and do not expect any unrelated > fallout. And for the reasons stated above I don't believe > anyone is using this since it's largely error prone. > and a regress chunk that avoids using such combination. note that this diff basically finishes previous attemts at modifying tests to match present syntax. diff --git regress/sbin/pfctl/pf48.in regress/sbin/pfctl/pf48.in index 540711a..a0dd143 100644 --- regress/sbin/pfctl/pf48.in +++ regress/sbin/pfctl/pf48.in @@ -1,12 +1,12 @@ table < regress > { 1.2.3.4 !5.6.7.8 10/8 lo0 } table const { ::1 fe80::/64 } table { 1.2.3.4 !5.6.7.8 } { ::1 ::2 ::3 } file "/dev/null" const { 4.3.2.1 } -match out on lo0 from < regress.1> to nat-to lo0:0 +match out on lo0 inet from < regress.1> to nat-to lo0:0 match out on !lo0 inet from ! to nat-to lo0:0 match in on lo0 inet6 from to rdr-to lo0:0 -match in on !lo0 from !< regress.1 > to rdr-to lo0:0 +match in on !lo0 inet6 from !< regress.1 > to rdr-to lo0:0 match in from { ! } to any match out from any to { !, } pass in from to any pass out from any to pass in from { } to any diff --git regress/sbin/pfctl/pf48.loaded regress/sbin/pfctl/pf48.loaded index 68b9854..cfdc8a2 100644 --- regress/sbin/pfctl/pf48.loaded +++ regress/sbin/pfctl/pf48.loaded @@ -1,7 +1,7 @@ -@0 match out on lo0 inet6 from to nat-to ::1 - [ Skip steps: d=2 p=end da=4 sp=end dp=end ] +@0 match out on lo0 inet from to nat-to 127.0.0.1 + [ Skip steps: d=2 f=2 p=end da=4 sp=end dp=end ] [ queue: qname= qid=0 pqname= pqid=0 ] [ Evaluations: 0 Packets: 0 Bytes: 0 States: 0 ] @1 match out on ! lo0 inet from ! to nat-to 127.0.0.1 [ Skip steps: p=end da=4 sp=end dp=end ] [ queue: qname= qid=0 pqname= pqid=0 ] diff --git regress/sbin/pfctl/pf48.ok regress/sbin/pfctl/pf48.ok index 5f6e6ab..aeccfcf 100644 --- regress/sbin/pfctl/pf48.ok +++ regress/sbin/pfctl/pf48.ok @@ -1,9 +1,9 @@ table { 1.2.3.4 !5.6.7.8 10.0.0.0/8 ::1 fe80::1 127.0.0.1 } table const { ::1 fe80::/64 } table const { 1.2.3.4 !5.6.7.8 ::1 ::2 ::3 } file "/dev/null" { 4.3.2.1 } -match out on lo0 inet6 from to nat-to ::1 +match out on lo0 inet from to nat-to 127.0.0.1 match out on ! lo0 inet from ! to nat-to 127.0.0.1 match in on lo0 inet6 from to rdr-to ::1 match in on ! lo0 inet6 from ! to rdr-to ::1 match in from to any match in from ! to any diff --git regress/sbin/pfctl/pf48.optimized regress/sbin/pfctl/pf48.optimized index 63309a7..90e2036 100644 --- regress/sbin/pfctl/pf48.optimized +++ regress/sbin/pfctl/pf48.optimized @@ -1,7 +1,7 @@ -@0 match out on lo0 inet6 from to nat-to ::1 - [ Skip steps: d=2 p=end da=4 sp=end dp=end ] +@0 match out on lo0 inet from to nat-to 127.0.0.1 + [ Skip steps: d=2 f=2 p=end da=4 sp=end dp=end ] [ queue: qname= qid=0 pqname= pqid=0 ] [ Evaluations: 0 Packets: 0 Bytes: 0 States: 0 ] @1 match out on ! lo0 inet from ! to nat-to 127.0.0.1 [ Skip steps: p=end da=4 sp=end dp=end ] [ queue: qname= qid=0 pqname= pqid=0 ] diff --git regress/sbin/pfctl/pf98.in regress/sbin/pfctl/pf98.in index a18a491..a224f9e 100644 --- regress/sbin/pfctl/pf98.in +++ regress/sbin/pfctl/pf98.in @@ -1,4 +1,4 @@ # Test rule order processing should pass (require-order no longer required) pass in on lo100 all -match out on lo0 all nat-to lo0 +match out on lo0 inet6 all nat-to lo0
pfctl: stricter redirect specs
Hi, Looking at some corner-cases I've realised that collapse_redirspec does a poor job of weeding out incompatibilities in the redirect pool specifications and hence inferring the rule address family from it. An example is a rule like this: pass out nat-to em0 Let's say that em0 has an IPv4 address 192.168.20.221 and an IPv6 link-local address fe80::221:86ff:fefa:5fc1. What this rule is supposed to do? Since it cannot create two rules out of this specification (the parser works), you have to choose whether this will be an IPv4 rule or an IPv6 rule. Quite some time ago for some reasons it translated to an IPv4 rule: pass out inet nat-to 192.168.20.221 Then the behaviour was changed (rather silently) and now it translates to an IPv6 rule: pass out inet6 nat-to fe80::221:86ff:fefa:5fc1 I think that both is somewhat unexpected, even less so the current behaviour. I propose to avoid the confusion by flagging such situations as errors, e.g.: % echo 'pass out nat-to { ::1 1.1.1.1 }' | ./obj/pfctl -o none -vnf - stdin:1: translation spec contains addresses with different address families stdin:1: skipping rule due to errors stdin:1: rule expands to no valid combination While previously it would pick only one of them (the first one): % echo 'pass out nat-to { ::1 1.1.1.1 }' | pfctl -o none -vnf - pass out inet6 all flags S/SA nat-to ::1 You are still able to use "em0" as a source/destination filter however: % echo 'pass out from em0' | pfctl -o none -vnf - pass out on em0 inet6 from fe80::221:86ff:fefa:5fc1 to any flags S/SA pass out inet from 192.168.20.221 to any flags S/SA meaning the diff only affects how nat-to/rdr-to pools are processed. I have carefully tested that and do not expect any unrelated fallout. And for the reasons stated above I don't believe anyone is using this since it's largely error prone. OK? P.S. binat bzero'ing is actually necessary since otherwise it contains garbage and we're now checking for it more carefully. diff --git sbin/pfctl/parse.y sbin/pfctl/parse.y index de9537e..ce80f8e 100644 --- sbin/pfctl/parse.y +++ sbin/pfctl/parse.y @@ -4295,11 +4295,11 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, struct redirspec *rs, u_int8_t allow_if) { struct pf_opt_tbl *tbl = NULL; struct node_host *h; struct pf_rule_addr ra; - int i = 0; + int af = 0, i = 0; if (!rs || !rs->rdr || rs->rdr->host == NULL) { rpool->addr.type = PF_ADDR_NONE; return (0); } @@ -4307,17 +4307,45 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, if (r->rule_flag & PFRULE_AFTO) r->naf = rs->af; /* count matching addresses */ for (h = rs->rdr->host; h != NULL; h = h->next) { - if (!r->af || !h->af || rs->af || h->af == r->af) { + if (h->af) { + /* check that af-to target address has correct af */ + if (rs->af && rs->af != h->af) { + yyerror("af mismatch in %s spec", + allow_if ? "routing" : "translation"); + return (1); + } + /* skip if the rule af doesn't match redirect af */ + if ((r->af && r->af != h->af) && /* exclude af-to */ + !(r->naf && h->af == r->naf)) + continue; + /* +* fail if the chosen af is not universal for the +* whole supplied redirect address pool +*/ + if (!r->af && af && af != h->af) { + yyerror("%s spec contains addresses with " + "different address families", + allow_if ? "routing" : "translation"); + return (1); + } + if (!r->af) + af = h->af; i++; - if (h->af && !r->af) - r->af = h->af; - } else if (r->naf && h->af == r->naf) + } else { + /* +* we silently allow any not af-specific host specs, +* e.g. (em0) and let the kernel deal with them +*/ i++; + } } + /* set rule af to one chosen above */ + if (!r->af && af) + r->af = af; if (i == 0) { /* no pool address */ yyerror("af mismatch in %s spec", allow_if ? "routing" : "translation"); return (1); @@ -4695,10 +4723,11 @@ expand_rule(struct pf_rule *r, int keeprule, struct node_if *interfaces,
Re: Undefined symbol in ld.so
On Tue, Jun 24, 2014 at 01:30:55AM -0700, William Orr wrote: > ld.so in -current isn't building right now, due to an undefined reference to > _dl_realloc caused by the recent addition of _dl_reallocarray. The following > diff implements _dl_realloc, largely copied from the implementation in > lib/libc/stdlib/malloc.c. There are cvssync problems. The code in curent compiles fine. -Otto > > tested on amd64 > > Index: malloc.c > === > RCS file: /cvs/src/libexec/ld.so/malloc.c,v > retrieving revision 1.1 > diff -u -b -w -p -r1.1 malloc.c > --- malloc.c 5 Jun 2014 08:39:07 - 1.1 > +++ malloc.c 24 Jun 2014 08:24:43 - > @@ -78,6 +78,12 @@ > #define MMAP(sz) _dl_mmap(NULL, (size_t)(sz), PROT_READ | PROT_WRITE, \ > MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) > > +#define MMAPA(a,sz) _dl_mmap((a), (size_t)(sz), PROT_READ | PROT_WRITE, \ > +MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) > + > +#define MQUERY(a, sz)_dl_mquery((a), (size_t)(sz), PROT_READ | > PROT_WRITE, \ > +MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, (off_t)0) > + > #define MMAP_ERROR(p)(_dl_mmap_error(p) ? MAP_FAILED : (p)) > > struct region_info { > @@ -277,6 +283,26 @@ unmap(struct dir_info *d, void *p, size_ > wrterror("malloc cache overflow"); > } > > +static void > +zapcacheregion(struct dir_info *d, void *p, size_t len) > +{ > + u_int i; > + struct region_info *r; > + size_t rsz; > + > + for (i = 0; i < mopts.malloc_cache; i++) { > + r = &d->free_regions[i]; > + if (r->p >= p && r->p <= (void *)((char *)p + len)) { > + rsz = r->size << MALLOC_PAGESHIFT; > + if (_dl_munmap(r->p, rsz)) > + wrterror("munmap"); > + r->p = NULL; > + d->free_regions_size -= r->size; > + r->size = 0; > + } > + } > +} > + > static void * > map(struct dir_info *d, size_t sz, int zero_fill) > { > @@ -987,6 +1013,119 @@ _dl_free(void *ptr) > malloc_active--; > } > > +static void * > +orealloc(void *p, size_t newsz) > +{ > + struct region_info *r; > + size_t oldsz, goldsz, gnewsz; > + void *q; > + > + if (p == NULL) > + return omalloc(newsz, 0); > + > + r = find(g_pool, p); > + if (r == NULL) { > + wrterror("bogus pointer (double free?)"); > + return NULL; > + } > + if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) > + return NULL; > + > + REALSIZE(oldsz, r); > + goldsz = oldsz; > + if (oldsz > MALLOC_MAXCHUNK) { > + if (oldsz < mopts.malloc_guard) > + wrterror("guard size"); > + oldsz -= mopts.malloc_guard; > + } > + > + gnewsz = newsz; > + if (gnewsz > MALLOC_MAXCHUNK) > + gnewsz += mopts.malloc_guard; > + > + if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p) { > + size_t roldsz = PAGEROUND(goldsz); > + size_t rnewsz = PAGEROUND(gnewsz); > + > + if (rnewsz > roldsz) { > + if (!mopts.malloc_guard) { > + void *hint = (char *)p + roldsz; > + size_t needed = rnewsz - roldsz; > + > + zapcacheregion(g_pool, hint, needed); > + q = MQUERY(hint, needed); > + if (q == hint) > + q = MMAPA(hint, needed); > + else > + q = MAP_FAILED; > + if (q == hint) { > + if (mopts.malloc_junk == 2) > + _dl_memset(q, SOME_JUNK, > needed); > + r->size = newsz; > + return p; > + } else if (q != MAP_FAILED) { > + if (_dl_munmap(q, needed)) > + wrterror("munmap"); > + } > + } > + } else if (rnewsz < roldsz) { > + if (mopts.malloc_guard) { > + if (_dl_mprotect((char *)p + roldsz - > + mopts.malloc_guard, mopts.malloc_guard, > + PROT_READ | PROT_WRITE)) > + wrterror("mprotect"); > + if (_dl_mprotect((char *)p + rnewsz - > + mopts.malloc_guard, mopts.malloc_guard, > + PROT_NONE)) > + wrterror("mprotect"); > + } > + unmap(g_pool, (char *)p + rne
Re: audio(9) manual page
On Tue, Jun 24, 2014 at 09:13:47AM +0200, Alexandre Ratchov wrote: > On Tue, Jun 24, 2014 at 03:58:41AM +0400, Alexander Polakov wrote: > > So I have been trying to write a new audio driver (for Xonar DS if > > anyone interested) and therefore reading audio(9). > > > > I was confused for a while by the use of "will" here. I think it's not > > clear enough that these functions should be called by the driver code. > > > > I'm not a native speaker, so may be it's just my lack of familiarity with > > english idioms. Sorry for the noise if that's the case. > > > > I see what you mean. As the manual describes the interface between > two layers we may need to be more precise about who calls who. > Wouldn't the following be less ambigous? > > When the hardware is ready to accept more samples the driver shall > call the > .Fa intr > function with the argument > .Fa intrarg . > the use of "will" is perfectly fine here - it's basically a conditional sentence structure. "shall" sounds awful. it sounds formal, dated, and like a document produced by posix. please don;t make this change. what is simpler, i think, and easier for most folks to understand, is using a present tense: When the hardware is ready to accept more samples, the driver calls the .Fa intr function with the argument .Fa intrarg . it's all a matter of taste, i suppose, but present tense structure does seem to be easier to read for non-native speakers (in my experience). jmc > > Index: audio.9 > > === > > RCS file: /cvs/src/share/man/man9/audio.9,v > > retrieving revision 1.23 > > diff -u -r1.23 audio.9 > > --- audio.9 21 Jan 2014 03:15:46 - 1.23 > > +++ audio.9 23 Jun 2014 19:42:42 - > > @@ -284,7 +284,7 @@ > > has been initiated (normally with DMA). > > When the hardware is ready to accept more samples the function > > .Fa intr > > -will be called with the argument > > +shall be called with the argument > > .Fa intrarg . > > Calling > > .Fa intr > > @@ -302,7 +302,7 @@ > > has been initiated (normally with DMA). > > When the hardware is ready to deliver more samples the function > > .Fa intr > > -will be called with the argument > > +shall be called with the argument > > .Fa intrarg . > > Calling > > .Fa intr > > @@ -437,7 +437,7 @@ > > .Fa blksize > > sized block, the function > > .Fa intr > > -will be called with the argument > > +shall be called with the argument > > .Fa intrarg > > (typically from the audio hardware interrupt service routine). > > Once started, the transfer may be stopped using > > @@ -459,7 +459,7 @@ > > .Fa blksize > > sized block, the function > > .Fa intr > > -will be called with the argument > > +shall be called with the argument > > .Fa intrarg > > (typically from the audio hardware interrupt service routine). > > Once started, the transfer may be stopped using >
Re: Undefined symbol in ld.so
On 06/24/14 09:30, William Orr wrote: > ld.so in -current isn't building right now, due to an undefined reference to > _dl_realloc caused by the recent addition of _dl_reallocarray. The following > diff implements _dl_realloc, largely copied from the implementation in > lib/libc/stdlib/malloc.c. > > tested on amd64 There are issues with some CVS mirrors because of cvsync/commitid's, one of those is issue is failure to update malloc.c, the current version is 1.3, you have version 1.1 your CVS source tree being incorrect is the issue. Try a different CVS mirror or wait until issues have been fixed. $ cvs log malloc.c RCS file: /cvs/src/libexec/ld.so/malloc.c,v Working file: malloc.c head: 1.3 branch: locks: strict access list: symbolic names: keyword substitution: kv total revisions: 3; selected revisions: 3 description: revision 1.3 date: 2014/06/21 08:00:23; author: otto; state: Exp; lines: +47 -1; commitid: wh9FTpEgwThWVeqE; Move to a non-zeroing _dl_malloc, a _dl_calloc and _dl_reallocarry and fix _dl_strdup to return NULL instead of crash; ok deraadt@ revision 1.2 date: 2014/06/15 06:48:30; author: otto; state: Exp; lines: +2 -2; commitid: zG8TjRrBxXrN0x6O; move to a smaller rbytes buffer; ok miod@ deraadt@ revision 1.1 date: 2014/06/05 08:39:07; author: otto; state: Exp; commitid: PovK1yhVqujrpswl; Move to (slightly stripped) version of libc malloc; ok deraadt@ = > > Index: malloc.c > === > RCS file: /cvs/src/libexec/ld.so/malloc.c,v > retrieving revision 1.1 > diff -u -b -w -p -r1.1 malloc.c > --- malloc.c 5 Jun 2014 08:39:07 - 1.1 > +++ malloc.c 24 Jun 2014 08:24:43 - > @@ -78,6 +78,12 @@ > #define MMAP(sz) _dl_mmap(NULL, (size_t)(sz), PROT_READ | PROT_WRITE, \ > MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) > > +#define MMAPA(a,sz) _dl_mmap((a), (size_t)(sz), PROT_READ | PROT_WRITE, \ > +MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) > + > +#define MQUERY(a, sz)_dl_mquery((a), (size_t)(sz), PROT_READ | > PROT_WRITE, \ > +MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, (off_t)0) > + > #define MMAP_ERROR(p)(_dl_mmap_error(p) ? MAP_FAILED : (p)) > > struct region_info { > @@ -277,6 +283,26 @@ unmap(struct dir_info *d, void *p, size_ > wrterror("malloc cache overflow"); > } > > +static void > +zapcacheregion(struct dir_info *d, void *p, size_t len) > +{ > + u_int i; > + struct region_info *r; > + size_t rsz; > + > + for (i = 0; i < mopts.malloc_cache; i++) { > + r = &d->free_regions[i]; > + if (r->p >= p && r->p <= (void *)((char *)p + len)) { > + rsz = r->size << MALLOC_PAGESHIFT; > + if (_dl_munmap(r->p, rsz)) > + wrterror("munmap"); > + r->p = NULL; > + d->free_regions_size -= r->size; > + r->size = 0; > + } > + } > +} > + > static void * > map(struct dir_info *d, size_t sz, int zero_fill) > { > @@ -987,6 +1013,119 @@ _dl_free(void *ptr) > malloc_active--; > } > > +static void * > +orealloc(void *p, size_t newsz) > +{ > + struct region_info *r; > + size_t oldsz, goldsz, gnewsz; > + void *q; > + > + if (p == NULL) > + return omalloc(newsz, 0); > + > + r = find(g_pool, p); > + if (r == NULL) { > + wrterror("bogus pointer (double free?)"); > + return NULL; > + } > + if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) > + return NULL; > + > + REALSIZE(oldsz, r); > + goldsz = oldsz; > + if (oldsz > MALLOC_MAXCHUNK) { > + if (oldsz < mopts.malloc_guard) > + wrterror("guard size"); > + oldsz -= mopts.malloc_guard; > + } > + > + gnewsz = newsz; > + if (gnewsz > MALLOC_MAXCHUNK) > + gnewsz += mopts.malloc_guard; > + > + if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p) { > + size_t roldsz = PAGEROUND(goldsz); > + size_t rnewsz = PAGEROUND(gnewsz); > + > + if (rnewsz > roldsz) { > + if (!mopts.malloc_guard) { > + void *hint = (char *)p + roldsz; > + size_t needed = rnewsz - roldsz; > + > + zapcacheregion(g_pool, hint, needed); > + q = MQUERY(hint, needed); > + if (q == hint) > + q = MMAPA(hint, needed); > + else > + q = MAP_FAILED; > + if (q == hint) { > + if (mopts.malloc_junk ==
Undefined symbol in ld.so
ld.so in -current isn't building right now, due to an undefined reference to _dl_realloc caused by the recent addition of _dl_reallocarray. The following diff implements _dl_realloc, largely copied from the implementation in lib/libc/stdlib/malloc.c. tested on amd64 Index: malloc.c === RCS file: /cvs/src/libexec/ld.so/malloc.c,v retrieving revision 1.1 diff -u -b -w -p -r1.1 malloc.c --- malloc.c5 Jun 2014 08:39:07 - 1.1 +++ malloc.c24 Jun 2014 08:24:43 - @@ -78,6 +78,12 @@ #define MMAP(sz) _dl_mmap(NULL, (size_t)(sz), PROT_READ | PROT_WRITE, \ MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) +#define MMAPA(a,sz)_dl_mmap((a), (size_t)(sz), PROT_READ | PROT_WRITE, \ +MAP_ANON | MAP_PRIVATE, -1, (off_t) 0) + +#define MQUERY(a, sz) _dl_mquery((a), (size_t)(sz), PROT_READ | PROT_WRITE, \ +MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, (off_t)0) + #define MMAP_ERROR(p) (_dl_mmap_error(p) ? MAP_FAILED : (p)) struct region_info { @@ -277,6 +283,26 @@ unmap(struct dir_info *d, void *p, size_ wrterror("malloc cache overflow"); } +static void +zapcacheregion(struct dir_info *d, void *p, size_t len) +{ + u_int i; + struct region_info *r; + size_t rsz; + + for (i = 0; i < mopts.malloc_cache; i++) { + r = &d->free_regions[i]; + if (r->p >= p && r->p <= (void *)((char *)p + len)) { + rsz = r->size << MALLOC_PAGESHIFT; + if (_dl_munmap(r->p, rsz)) + wrterror("munmap"); + r->p = NULL; + d->free_regions_size -= r->size; + r->size = 0; + } + } +} + static void * map(struct dir_info *d, size_t sz, int zero_fill) { @@ -987,6 +1013,119 @@ _dl_free(void *ptr) malloc_active--; } +static void * +orealloc(void *p, size_t newsz) +{ + struct region_info *r; + size_t oldsz, goldsz, gnewsz; + void *q; + + if (p == NULL) + return omalloc(newsz, 0); + + r = find(g_pool, p); + if (r == NULL) { + wrterror("bogus pointer (double free?)"); + return NULL; + } + if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) + return NULL; + + REALSIZE(oldsz, r); + goldsz = oldsz; + if (oldsz > MALLOC_MAXCHUNK) { + if (oldsz < mopts.malloc_guard) + wrterror("guard size"); + oldsz -= mopts.malloc_guard; + } + + gnewsz = newsz; + if (gnewsz > MALLOC_MAXCHUNK) + gnewsz += mopts.malloc_guard; + + if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p) { + size_t roldsz = PAGEROUND(goldsz); + size_t rnewsz = PAGEROUND(gnewsz); + + if (rnewsz > roldsz) { + if (!mopts.malloc_guard) { + void *hint = (char *)p + roldsz; + size_t needed = rnewsz - roldsz; + + zapcacheregion(g_pool, hint, needed); + q = MQUERY(hint, needed); + if (q == hint) + q = MMAPA(hint, needed); + else + q = MAP_FAILED; + if (q == hint) { + if (mopts.malloc_junk == 2) + _dl_memset(q, SOME_JUNK, needed); + r->size = newsz; + return p; + } else if (q != MAP_FAILED) { + if (_dl_munmap(q, needed)) + wrterror("munmap"); + } + } + } else if (rnewsz < roldsz) { + if (mopts.malloc_guard) { + if (_dl_mprotect((char *)p + roldsz - + mopts.malloc_guard, mopts.malloc_guard, + PROT_READ | PROT_WRITE)) + wrterror("mprotect"); + if (_dl_mprotect((char *)p + rnewsz - + mopts.malloc_guard, mopts.malloc_guard, + PROT_NONE)) + wrterror("mprotect"); + } + unmap(g_pool, (char *)p + rnewsz, roldsz - rnewsz); + r->size = gnewsz; + return p; + } else { + if (newsz > oldsz && mopts.malloc_junk == 2) + _dl_memset((char *)p + newsz,
Re: audio(9) manual page
On Tue, Jun 24, 2014 at 03:58:41AM +0400, Alexander Polakov wrote: > So I have been trying to write a new audio driver (for Xonar DS if > anyone interested) and therefore reading audio(9). > > I was confused for a while by the use of "will" here. I think it's not > clear enough that these functions should be called by the driver code. > > I'm not a native speaker, so may be it's just my lack of familiarity with > english idioms. Sorry for the noise if that's the case. > I see what you mean. As the manual describes the interface between two layers we may need to be more precise about who calls who. Wouldn't the following be less ambigous? When the hardware is ready to accept more samples the driver shall call the .Fa intr function with the argument .Fa intrarg . > Index: audio.9 > === > RCS file: /cvs/src/share/man/man9/audio.9,v > retrieving revision 1.23 > diff -u -r1.23 audio.9 > --- audio.9 21 Jan 2014 03:15:46 - 1.23 > +++ audio.9 23 Jun 2014 19:42:42 - > @@ -284,7 +284,7 @@ > has been initiated (normally with DMA). > When the hardware is ready to accept more samples the function > .Fa intr > -will be called with the argument > +shall be called with the argument > .Fa intrarg . > Calling > .Fa intr > @@ -302,7 +302,7 @@ > has been initiated (normally with DMA). > When the hardware is ready to deliver more samples the function > .Fa intr > -will be called with the argument > +shall be called with the argument > .Fa intrarg . > Calling > .Fa intr > @@ -437,7 +437,7 @@ > .Fa blksize > sized block, the function > .Fa intr > -will be called with the argument > +shall be called with the argument > .Fa intrarg > (typically from the audio hardware interrupt service routine). > Once started, the transfer may be stopped using > @@ -459,7 +459,7 @@ > .Fa blksize > sized block, the function > .Fa intr > -will be called with the argument > +shall be called with the argument > .Fa intrarg > (typically from the audio hardware interrupt service routine). > Once started, the transfer may be stopped using