>Synopsis: RLIMIT_CPU doesn't work reliably on mostly idle systems
>Category: system
>Environment:
System : OpenBSD 7.3
Details : OpenBSD 7.3 (GENERIC.MP) #1242: Sat Mar 25 18:04:31 MDT
2023
[email protected]:/usr/src/sys/arch/octeon/compile/GENERIC.MP
Architecture: OpenBSD.octeon
Machine : octeon
>Description:
RLIMIT_CPU doesn't work reliably when few/no syscalls are made on an
otherwise idle system (aside from the test process using up CPU).
It can take 20-50s to fire SIGKILL with rlim_max=9 (and the SIGXCPU
from rlim_cur=1 won't even fire).
I can reproduce this on a private amd64 VM and also on gcc231
on GCC compiler farm <https://cfarm.tetaneutral.net/>.
I can't reproduce this on a busy system like gcc220 on cfarm,
however.
>How-To-Repeat:
Following is a standalone C program which demonstrates the problem on
a mostly idle system:
/*
* Most reliably reproduced with compiler optimizations disabled:
*
* cc -o rlimit_cpu -ggdb3 -Wall rlimit_cpu.c
*
* Neither SIGXCPU (from rlim_cur) nor SIGKILL (from rlim_max)
* with RLIMIT_CPU set seem to fire reliably with few syscalls being made.
* On an otherwise idle system, it can take many more seconds (20-50s)
* than expected when rlim_max=9 (SIGXCPU doesn't even happen).
* Best case is 2 seconds for SIGXCPU when rlim_cur=1 on a busy system
* which is understandable due to kernel accounting delays.
*
* I rely on RLIMIT_CPU to protect systems from pathological userspace
* code (diff generation, regexps, etc)
*
* Testing on cfarm <https://cfarm.tetaneutral.net/> machines,
* the issue is visible on a mostly-idle 4-core gcc231 mips64
* but doesn't seem to happen on the busy 12-core gcc220 machine
* (only 2 seconds for XCPU w/ rlim_cur=1)
*/
#include <sys/resource.h>
#include <assert.h>
#include <signal.h>
#include <unistd.h>
static void sigxcpu(int sig)
{
write(1, "SIGXCPU\n", 8);
_exit(1);
}
static volatile size_t nr; // volatile to disable optimizations
int main(void)
{
struct rlimit rlim = { .rlim_cur = 1, .rlim_max = 9 };
int rc;
signal(SIGXCPU, sigxcpu);
rc = setrlimit(RLIMIT_CPU, &rlim);
assert(rc == 0);
/*
* adding some time, times, and write syscalls improve likelyhood of
* of rlimit signals firing in a timely manner. writes to /dev/null
* seems less-likely to trigger than writes to the terminal or
* regular file.
*/
for (;; nr++) {
}
return 0;
}
>Fix:
Making more syscalls can workaround the problem, but that's not
an option when dealing with userspace-heavy code like pathological regexps.
dmesg:
OpenBSD 7.3 (GENERIC.MP) #1242: Sat Mar 25 18:04:31 MDT 2023
[email protected]:/usr/src/sys/arch/octeon/compile/GENERIC.MP
real mem = 1073741824 (1024MB)
avail mem = 1035304960 (987MB)
random: good seed from bootblocks
mainbus0 at root: board 20300 rev 0.15, model cavium,ubnt_e300
cpu0 at mainbus0: CN70xx/CN71xx CPU rev 0.2 1000 MHz, CN70xx/CN71xx FPU rev 0.0
cpu0: cache L1-I 78KB 39 way D 32KB 32 way, L2 1024KB 8 way
cpu1 at mainbus0: CN70xx/CN71xx CPU rev 0.2 1000 MHz, CN70xx/CN71xx FPU rev 0.0
cpu1: cache L1-I 78KB 39 way D 32KB 32 way, L2 1024KB 8 way
cpu2 at mainbus0: CN70xx/CN71xx CPU rev 0.2 1000 MHz, CN70xx/CN71xx FPU rev 0.0
cpu2: cache L1-I 78KB 39 way D 32KB 32 way, L2 1024KB 8 way
cpu3 at mainbus0: CN70xx/CN71xx CPU rev 0.2 1000 MHz, CN70xx/CN71xx FPU rev 0.0
cpu3: cache L1-I 78KB 39 way D 32KB 32 way, L2 1024KB 8 way
clock0 at mainbus0: int 5
octcrypto0 at mainbus0
iobus0 at mainbus0
simplebus0 at iobus0: "soc"
"bootbus" at simplebus0 not configured
octciu0 at simplebus0
octcib0 at simplebus0: max-bits 23
octcib1 at simplebus0: max-bits 12
octcib2 at simplebus0: max-bits 6
octcib3 at simplebus0: max-bits 15
octcib4 at simplebus0: max-bits 4
octcib5 at simplebus0: max-bits 11
octcib6 at simplebus0: max-bits 11
octgpio0 at simplebus0: 20 pins, xbit 16
octsmi0 at simplebus0
octsmi1 at simplebus0
octpip0 at simplebus0
octgmx0 at octpip0 interface 0
cnmac0 at octgmx0: port 0 SGMII, address e0:63:da:c0:62:27
ukphy0 at cnmac0 phy 4: Generic IEEE 802.3u media interface, rev. 2: OUI
0x0001c1, model 0x000c
cnmac1 at octgmx0: port 1 SGMII, address e0:63:da:c0:62:28
ukphy1 at cnmac1 phy 5: Generic IEEE 802.3u media interface, rev. 2: OUI
0x0001c1, model 0x000c
cnmac2 at octgmx0: port 2 SGMII, address e0:63:da:c0:62:29
ukphy2 at cnmac2 phy 6: Generic IEEE 802.3u media interface, rev. 2: OUI
0x0001c1, model 0x000c
cnmac3 at octgmx0: port 3 SGMII, address e0:63:da:c0:62:2a
ukphy3 at cnmac3 phy 7: Generic IEEE 802.3u media interface, rev. 2: OUI
0x0001c1, model 0x000c
octsctl0 at simplebus0: disabled
octxctl0 at simplebus0: DWC3 rev 0x250a
xhci0 at octxctl0, xHCI 1.0
usb0 at xhci0: USB revision 3.0
uhub0 at usb0 configuration 1 interface 0 "Generic xHCI root hub" rev 3.00/1.00
addr 1
octxctl1 at simplebus0: DWC3 rev 0x250a
xhci1 at octxctl1, xHCI 1.0
usb1 at xhci1: USB revision 3.0
uhub1 at usb1 configuration 1 interface 0 "Generic xHCI root hub" rev 3.00/1.00
addr 1
"i2c" at simplebus0 not configured
"i2c" at simplebus0 not configured
com0 at simplebus0: ns16550a, 64 byte fifo
com0: console
com1 at simplebus0: ns16550a, 64 byte fifo
com1: probed fifo depth: 0 bytes
octmmc0 at simplebus0
sdmmc0 at octmmc0: 8-bit, mmc high-speed
"spi" at simplebus0 not configured
"ocla0" at simplebus0 not configured
"dma-engine" at simplebus0 not configured
"dma-engine" at simplebus0 not configured
octrng0 at iobus0 base 0x1400000000000 irq 0
octpcie0 at iobus0: 3 ports
octpcie0 port 0: link timeout
octpcie0 port 1: reset timeout
octpcie0 port 2: reset timeout
umass0 at uhub0 port 2 configuration 1 interface 0 "asmedia ASMT1153E" rev
3.00/1.00 addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets, initiator 0
sd0 at scsibus0 targ 1 lun 0: <asmedia, ASMT1153E, 0>
serial.174c55aa123456789010
sd0: 953869MB, 512 bytes/sector, 1953525168 sectors
scsibus1 at sdmmc0: 2 targets, initiator 0
sd1 at scsibus1 targ 1 lun 0: <Kingston, MMC4GB, 0000> removable
sd1: 3728MB, 512 bytes/sector, 7634944 sectors
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
root on sd0a (12d0a02327a609ac.a) swap on sd0b dump on sd0b
WARNING: /mnt was not properly unmounted
WARNING: CHECK AND RESET THE DATE!
usbdevs:
usbdevs: no USB controllers found