Display parameters exposed to userland as percentages (backlight, brightness,
authormiod <miod@openbsd.org>
Fri, 8 Jul 2022 21:29:20 +0000 (21:29 +0000)
committermiod <miod@openbsd.org>
Fri, 8 Jul 2022 21:29:20 +0000 (21:29 +0000)
contrast) are not valid if they only have one state, i.e. minimum and maximum
values being equal.

Do not expose them to userland in this case, for wsconsctl would attempt to
divide by zero (which is known to have unwelcome consequences).

This allows display drivers trusting not-so-reliable sources (fdt, bogus
hardware...) to not have to perform those checks themselves.

Found the hard way by daniel@. No firm consensus on this workaround, using
one seniority point here, will revert if this spawns complaints.

sys/dev/wscons/wsdisplay.c

index 4a3afb1..b86602e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsdisplay.c,v 1.147 2022/07/05 15:06:16 visa Exp $ */
+/* $OpenBSD: wsdisplay.c,v 1.148 2022/07/08 21:29:20 miod Exp $ */
 /* $NetBSD: wsdisplay.c,v 1.82 2005/02/27 00:27:52 perry Exp $ */
 
 /*
@@ -147,6 +147,8 @@ void        wsdisplay_suspend_device(struct device *);
 void   wsdisplay_addscreen_print(struct wsdisplay_softc *, int, int);
 void   wsdisplay_closescreen(struct wsdisplay_softc *, struct wsscreen *);
 int    wsdisplay_delscreen(struct wsdisplay_softc *, int, int);
+int    wsdisplay_driver_ioctl(struct wsdisplay_softc *, u_long, caddr_t,
+           int, struct proc *);
 
 void   wsdisplay_burner_setup(struct wsdisplay_softc *, struct wsscreen *);
 void   wsdisplay_burner(void *v);
@@ -1100,9 +1102,7 @@ int
 wsdisplay_param(struct device *dev, u_long cmd, struct wsdisplay_param *dp)
 {
        struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
-
-       return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
-           (caddr_t)dp, 0, NULL));
+       return wsdisplay_driver_ioctl(sc, cmd, (caddr_t)dp, 0, NULL);
 }
 
 int
@@ -1293,8 +1293,31 @@ wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr,
         }
 
        /* check ioctls for display */
-       return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
+       return wsdisplay_driver_ioctl(sc, cmd, data, flag, p);
+}
+
+int
+wsdisplay_driver_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data,
+    int flag, struct proc *p)
+{
+       int error;
+
+       error = ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
            flag, p));
+       /* Do not report parameters with empty ranges to userland. */
+       if (error == 0 && cmd == WSDISPLAYIO_GETPARAM) {
+               struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
+               switch (dp->param) {
+               case WSDISPLAYIO_PARAM_BACKLIGHT:
+               case WSDISPLAYIO_PARAM_BRIGHTNESS:
+               case WSDISPLAYIO_PARAM_CONTRAST:
+                       if (dp->min == dp->max)
+                               error = ENOTTY;
+                       break;
+               }
+       }
+
+       return error;
 }
 
 int