git: ae5ad9c6a79b - stable/15 - amd64: do not allow to set IOPL to 3 when FRED is used

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 03 Nov 2026 09:02:05 UTC
The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=ae5ad9c6a79b29b7092323b3bc284fa3f21c213d

commit ae5ad9c6a79b29b7092323b3bc284fa3f21c213d
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-10-27 09:10:09 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-11-03 09:01:14 +0000

    amd64: do not allow to set IOPL to 3 when FRED is used
    
    (cherry picked from commit 5bc997b6f5b1265ff28d11405eb980bf471c3db4)
---
 sys/amd64/amd64/io.c                | 16 ++++++++++++----
 sys/amd64/linux/linux_machdep.c     |  3 +++
 sys/amd64/linux32/linux32_machdep.c |  3 +++
 sys/dev/syscons/syscons.c           |  3 +++
 sys/dev/vt/vt_core.c                |  3 +++
 5 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/sys/amd64/amd64/io.c b/sys/amd64/amd64/io.c
index 6c36d5fb20e1..ba34675c0cc5 100644
--- a/sys/amd64/amd64/io.c
+++ b/sys/amd64/amd64/io.c
@@ -31,21 +31,29 @@
 
 #include <machine/frame.h>
 #include <machine/iodev.h>
+#include <machine/md_var.h>
 #include <machine/psl.h>
 
 int
 iodev_open(struct thread *td)
 {
-
-	td->td_frame->tf_rflags |= PSL_IOPL;
+	/*
+	 * SDM rev. 93 vol.3 8.4.2.1 Loading and Checking the Return State:
+	 * Checking IOPL ensures that, when FRED transitions are
+	 * enabled, IOPL is always 0 when CPL = 3.
+	 *
+	 * As result, io(4) cannot enable the IOPL for usermode on FRED.
+	 */
+	if (!fred)
+		td->td_frame->tf_rflags |= PSL_IOPL;
 	return (0);
 }
 
 int
 iodev_close(struct thread *td)
 {
-
-	td->td_frame->tf_rflags &= ~PSL_IOPL;
+	if (!fred)
+		td->td_frame->tf_rflags &= ~PSL_IOPL;
 	return (0);
 }
 
diff --git a/sys/amd64/linux/linux_machdep.c b/sys/amd64/linux/linux_machdep.c
index dc7f55f6f198..e22a3ed22c31 100644
--- a/sys/amd64/linux/linux_machdep.c
+++ b/sys/amd64/linux/linux_machdep.c
@@ -88,6 +88,9 @@ linux_iopl(struct thread *td, struct linux_iopl_args *args)
 		return (error);
 	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
 		return (error);
+	/* See comment in sys/amd64/amd64/io.c. */
+	if (fred && args->level != 0)
+		return (ENOSYS);
 	td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) |
 	    (args->level * (PSL_IOPL / 3));
 
diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c
index a9517b42a4d9..a62965308c33 100644
--- a/sys/amd64/linux32/linux32_machdep.c
+++ b/sys/amd64/linux32/linux32_machdep.c
@@ -332,6 +332,9 @@ linux_iopl(struct thread *td, struct linux_iopl_args *args)
 		return (error);
 	if ((error = securelevel_gt(td->td_ucred, 0)) != 0)
 		return (error);
+	/* See comment in sys/amd64/amd64/io.c. */
+	if (fred && args->level != 0)
+		return (ENOSYS);
 	td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) |
 	    (args->level * (PSL_IOPL / 3));
 
diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c
index e9d664f51a1f..29892d4caa92 100644
--- a/sys/dev/syscons/syscons.c
+++ b/sys/dev/syscons/syscons.c
@@ -72,6 +72,7 @@
 #if defined(__i386__) || defined(__amd64__)
 #include <machine/psl.h>
 #include <machine/frame.h>
+#include <machine/md_var.h>
 #endif
 
 #if defined(__amd64__) || defined(__i386__)
@@ -1338,6 +1339,8 @@ sctty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
 #ifdef __i386__
 		td->td_frame->tf_eflags |= PSL_IOPL;
 #elif defined(__amd64__)
+		if (fred)
+			return (EINVAL);
 		td->td_frame->tf_rflags |= PSL_IOPL;
 #endif
 		return 0;
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 922b44028a23..f28515b0771a 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -61,6 +61,7 @@
 #if defined(__i386__) || defined(__amd64__)
 #include <machine/psl.h>
 #include <machine/frame.h>
+#include <machine/md_var.h>
 #endif
 
 static int vtterm_cngrab_noswitch(struct vt_device *, struct vt_window *);
@@ -2937,6 +2938,8 @@ skip_thunk:
 #if defined(__i386__)
 		td->td_frame->tf_eflags |= PSL_IOPL;
 #elif defined(__amd64__)
+		if (fred)
+			return (EINVAL);
 		td->td_frame->tf_rflags |= PSL_IOPL;
 #endif
 		return (0);