NetBSD Problem Report #58972

From www@netbsd.org  Tue Jan  7 09:21:19 2025
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits)
	 client-signature RSA-PSS (2048 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 3FB031A9238
	for <gnats-bugs@gnats.NetBSD.org>; Tue,  7 Jan 2025 09:21:19 +0000 (UTC)
Message-Id: <20250107092117.B30531A923B@mollari.NetBSD.org>
Date: Tue,  7 Jan 2025 09:21:17 +0000 (UTC)
From: rvp@SDF.ORG
Reply-To: rvp@SDF.ORG
To: gnats-bugs@NetBSD.org
Subject: madvise(MADV_WILLNEED) on EFI genfb framebuffer crashes kernel
X-Send-Pr-Version: www-1.0

>Number:         58972
>Category:       kern
>Synopsis:       madvise(MADV_WILLNEED) on EFI genfb framebuffer crashes kernel
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Jan 07 09:25:00 +0000 2025
>Last-Modified:  Wed Jan 08 06:25:01 +0000 2025
>Originator:     RVP
>Release:        NetBSD/amd64 10.99.12
>Organization:
>Environment:
NetBSD/amd64 10.99.12 GENERIC about a week old.
>Description:
In trying to find why genfb + wsfb(4) was so slow on NetBSD (twice as
slow as FreeBSD for OpenGL running on its efifb + scfb(4)), I wrote a
demo (which is not the one below) and then tried to speed it up by using
mlock() and madvise() on the framebuffer (this seems to have no effect).

Using mlock() causes the kernel to massively spew the console like
this:

```
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x76499355d000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x76499355e000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x76499355f000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993560000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993561000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993562000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993563000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993564000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993565000 did not change!
[   145.746480] pmap_unwire: wiring for pmap 0xffffa3ef7e409c00 va 0x764993566000 did not change!
```

Hundreds of these messages spew on every tick. Bad, but not fatal.

Doing madvise() however, crashes the kernel (as _any_ user--no root reqd.)
in uvm_readahead(). Mebbe madvise() should do nothing on framebuffer
devices (like on Linux)?

>How-To-Repeat:
Compile and run the reproducer as follows (only EFI genfb console tested):

```
cc -DDO_MLOCK_UNWIRE_SPEW -o t1 fbtest.c
cc -DDO_MADV_CRASH_KERNEL -o t2 fbtest.c
./t1; clear; read x; ./t2
```

Reproducer:

```
/**
 * NetBSD wsdisplay(4) framebuffer test.
 */

#include <sys/ioctl.h>
#include <sys/mman.h>

#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <dev/wscons/wsconsio.h>

typedef struct framebuffer {
	int fd;
	uint32_t xres;
	uint32_t yres;
	uint32_t bpp;		/* bytes per pixel */
	uint32_t stride;
	u_int omode;
	size_t len;
	size_t mapsz;
	void* fb;
} Framebuffer;

static Framebuffer* fb_init(char* fbdev);
static void fb_clear(Framebuffer* fb);
static void fb_done(Framebuffer* fb);

int
main(void)
{
	Framebuffer* fb;
	char* devname;
	int rc = EXIT_FAILURE;

	if (getenv("DISPLAY") != NULL)
		errx(rc, "run this on a framebuffer-console--ie. not in X");

	devname = ttyname(STDIN_FILENO);
	if (devname == NULL)
		devname = "/dev/ttyE0";

	fb = fb_init(devname);
	if (fb == NULL)
		err(rc, "error initializing framebuffer: %s", devname);
	fb_clear(fb);
	fb_done(fb);

	return EXIT_SUCCESS;
}

static Framebuffer*
fb_init(char* fbdev)
{
	struct wsdisplayio_fbinfo fbi;
	u_int omode, mode;
	size_t pagemask;
	Framebuffer* fb = NULL;

	int fd = open(fbdev, O_RDWR);
	if (fd == -1) {
		warn("%s: open failed", fbdev);
		return NULL;
	}

	if (ioctl(fd, WSDISPLAYIO_GET_FBINFO, &fbi) == -1) {
		warn("ioctl(WSDISPLAYIO_GET_FBINFO) failed");
		return NULL;
	}
	if (fbi.fbi_bitsperpixel != 32) {
		warnx("Framebuffer depth (%d) != 32", fbi.fbi_bitsperpixel);
		return NULL;
	}
#define ROFF	fbi.fbi_subtype.fbi_rgbmasks
	if (ROFF.red_offset != 16 || ROFF.green_offset != 8 || ROFF.blue_offset != 0) {
		warnx("FB pixel layout not BGRA");
		return NULL;
	}
#undef ROFF
	if (ioctl(fd, WSDISPLAYIO_GMODE, &omode) == -1) {
		warn("ioctl(WSDISPLAYIO_GMODE) failed");
		return NULL;
	}
	mode = WSDISPLAYIO_MODE_DUMBFB;
	if (ioctl(fd, WSDISPLAYIO_SMODE, &mode) == -1) {
		warn("can't switch to dumb FB mode");
		return NULL;
	}

	if ((fb = malloc(sizeof (Framebuffer))) == NULL) {
		warn("error allocating FB struct");
		return NULL;
	}
	fb->fd = fd;
	fb->fb = NULL;
	fb->xres = fbi.fbi_width;
	fb->yres = fbi.fbi_height;
	fb->bpp = fbi.fbi_bitsperpixel / 8;	/* bytes per pixel */
	fb->stride = fbi.fbi_stride;		/* bytes, not pixels */
	fb->omode = omode;			/* save orig. mode */
	fb->len = fbi.fbi_fbsize;		/* should be == stride * yres */
	pagemask = getpagesize() - 1;
	fb->mapsz = (fb->len + pagemask) & ~pagemask;

	fb->fb = mmap(0, fb->mapsz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)0);
	if ((void* )fb->fb == MAP_FAILED) {
		warn("error mapping framebuffer");
		free(fb);
		return NULL;
	}

#ifdef DO_MADV_CRASH_KERNEL
	if (madvise(fb->fb, fb->mapsz, MADV_WILLNEED) == -1)
		warn("madvise(MADV_WILLNEED) failed");
#endif

#ifdef DO_MLOCK_UNWIRE_SPEW
	if (mlock(fb->fb, fb->mapsz) != 0)
		warn("error locking FB memory");
#endif

	return fb;
}

static void
fb_clear(Framebuffer* fb)
{
	memset(fb->fb, 0, fb->len);
}

static void
fb_done(Framebuffer* fb)
{
	if (munmap(fb->fb, fb->mapsz) == -1)
		warn("munmap() failed");
	if (ioctl(fb->fd, WSDISPLAYIO_SMODE, &fb->omode) == -1)
		warn("can't switch to orig. mode");
	close(fb->fd);
	free(fb);
}
```

>Fix:
No idea, but, users shouldn't be able to crash the kernel so easily.

>Audit-Trail:
From: RVP <rvp@SDF.ORG>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/58972: madvise(MADV_WILLNEED) on EFI genfb framebuffer
 crashes kernel
Date: Wed, 8 Jan 2025 06:23:16 +0000 (UTC)

 On Tue, 7 Jan 2025, rvp@SDF.ORG wrote:

 > Doing madvise() however, crashes the kernel (as _any_ user--no root reqd.)
 > in uvm_readahead().
 >

 The exact log is:

 ```
 [   131.111980] prevented execution of 0x0 (SMEP)
 [   131.111980] fatal page fault in supervisor mode
 [   131.111980] trap type 6 code 0x10 rip 0 cs 0x8 rflags 0x10246 cr2 0 ilevel 0 rsp 0xffffd1026969dea8
 [   131.111980] curlwp 0xffffa2762ee7b400 pid 346.346 lowest kstack 0xffffd102696992c0
 [   131.111980] panic: trap
 [   131.111980] cpu1: Begin traceback...
 [   131.111980] vpanic() at netbsd:vpanic+0x171
 [   131.111980] panic() at netbsd:panic+0x3c
 [   131.111980] trap() at netbsd:trap+0xb44
 [   131.111980] --- trap (number 6) ---
 [   131.111980] ?() at 0
 [   131.111980] uvm_readahead() at netbsd:uvm_readahead+0x3d
 [   131.111980] uvm_map_willneed() at netbsd:uvm_map_willneed+0xdb
 [   131.111980] syscall() at netbsd:syscall+0x112
 [   131.111980] --- syscall (number 75) ---
 [   131.111980] netbsd:syscall+0x112:
 [   131.111980] cpu1: End traceback...
 [   131.111980] dumping to dev 168,10 (offset=76055, size=2038493):
 ```

 > Mebbe madvise() should do nothing on framebuffer devices (like on Linux)?
 >

 ... and, this seems to fix it:


 ```
 diff -urN a/src/sys/uvm/uvm_readahead.c b/src/sys/uvm/uvm_readahead.c
 --- a/src/sys/uvm/uvm_readahead.c	2023-09-23 18:21:12.000000000 +0000
 +++ b/src/sys/uvm/uvm_readahead.c	2025-01-07 23:26:06.084960295 +0000
 @@ -350,6 +350,9 @@
   uvm_readahead(struct uvm_object *uobj, off_t off, off_t size)
   {

 +	if (uobj->pgops->pgo_get == NULL)
 +		return EOPNOTSUPP;
 +
   	/*
   	 * don't allow too much read-ahead.
   	 */
 ```

 -RVP

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2025 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.