Compare commits

...
10 Commits
Author SHA1 Message Date
Siva Mahadevan d9d6e77965 tests/pf/igmp: fix attribute error with newer versions of scapy
This fixes the flaky testcase in CI[0].

While here:
* fix a typo in a comment
* remove an unnecessary import
* fix this deprecation warning:

  /usr/local/lib/python3.12/site-packages/scapy/contrib/igmp.py:12:
  DeprecationWarning: scapy.contrib.igmp is deprecated. Please use
  scapy.layers.igmp instead !

[0] https://ci.freebsd.org/job/FreeBSD-main-amd64-test/29813/testReport/junit/sys.netpfil.pf.igmp/py/TestIGMP__test_ip_opts/

Reviewed by:	kp
MFC after:	3 days
Sponsored by:	The FreeBSD Foundation
2026-10-27 12:54:20 -04:00
Mark Johnston eca7cba74c virtio_p9fs: Mark response buffers as initialized for KMSAN
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
2026-10-27 15:03:52 +00:00
Konstantin Belousov 73b3fb41e6 amd64: Make the SYSENTER and INTn action same as for IDT case.
Fixes:	6e93f5e4d6 ("amd64: FRED support")
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
2026-10-27 13:59:41 +02:00
Konstantin Belousov 8671e823b7 amd64: do not pass SYSENTER frame to FRED fast syscall handler
With FRED, SYSCALL is delivered as event type syscall (7) and vector 1.
SYSENTER is syscall with vector 2.  Handle SYSENTER in slow path,
otherwise 32bit code is able to execute 64bit syscalls.

Also check that SYSCALL comes from the 64bit mode. Intel already
specifies that SYSCALL causes #UD in compatibility mode, but there is no
AMD specification for SYSCALL under FRED yet, and SYSCALL is allowed
in compatibility mode on AMD with IDT event delivery.

Fixes:	6e93f5e4d6 ("amd64: FRED support")
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
2026-10-27 13:59:41 +02:00
Konstantin Belousov 473cd1bba9 amd64: fixes for register handling of syscall entry for FRED
- Save %r10 into tf_rcx.  This is the location for the 4th arg.
  libsys stubs do 'movq %rcx, %r10' so the fast syscall path works
  as is.  But Go binaries directly put arg 4 into %r10.
  Also save %r11 into tf_r11 for the duration of syscall handler.
- Somewhat improve binary compatibility with IDT SYSCALL fast return,
  by copying userspace return %rip into %rcx, and %rflags into %r11,
  emulating SYSCALL IDT delivery.

Fixes:	6e93f5e4d6 ("amd64: FRED support")
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
2026-10-27 13:58:48 +02:00
Konstantin Belousov 5bc997b6f5 amd64: do not allow to set IOPL to 3 when FRED is used
SDM requires that IOPL is zero when returning to usermode with ERETU.

Do not set rflags.iopl for FreeBSD io(4) open.
This might be changed to disallow io(4) open for FRED at all with a
knob, if there is a real need.

Return ENOSYS from linux iopl(2), apparently Linux kernel can be
configured without iopl(2) support, so linux programs should be prepared
for this error.

Return EINVAL from vt(4)/syscons(4) ioctl(KDENABIO).

Fixes:	6e93f5e4d6 ("amd64: FRED support")
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
2026-10-27 13:58:48 +02:00
Konstantin Belousov e86a612d77 trap_fred_handle_k_exc(): handle #AC in kernel
Fixes:	c6d7235ac1 ("amd64: handle #AC in kernel mode")
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
2026-10-27 13:58:48 +02:00
Konstantin Belousov 787e2e411d amd64_cpu_init_fred(): set stack level for NMI and not #NM
Fixes:	6e93f5e4d6 ("amd64: FRED support")
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
2026-10-27 13:58:48 +02:00
Christos Margiolis eb36c35ccf sound tests: Check the return value of close(2)
While here, remove two munmap(2) calls on mappings the tests require to
have failed, since they are practically dead.

MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D60800
2026-10-27 12:27:32 +01:00
Christos Margiolis 5760c22a05 sound: Let pcm_unregister() tear down a partially initialized device
Since 3107b952f5 ("sound: Merge PCM_ALIVE() with PCM_REGISTERED()"),
pcm_unregister() is gated on PCM_REGISTERED(), so it cannot run unless
pcm_register() has already succeeded, which means drivers will leak
resources if a failure happened prior to this.

Reintroduce PCM_ALIVE(), but test dev rather than the lock. pcm_init()
assigns dev before anything else, so it can tell us whether pcm_init()
has run or not. Make sure to clear it in pcm_unregister() so that a
second call to pcm_unregister() cannot double-free.

While here, publish to sndstat(4) only once pcm_register() has
succeeded.

Reported by:	jah
Fixes:		3107b952f5 ("sound: Merge PCM_ALIVE() with PCM_REGISTERED()")
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Reviewed by:	jah, markj
Differential Revision:	https://reviews.freebsd.org/D60801
2026-10-27 12:26:29 +01:00
17 changed files with 106 additions and 51 deletions

No files matched your search

+8 -6
View File
@@ -1428,7 +1428,7 @@ gsbase_load_fault:
ALIGN_TEXT
user_fred_syscall:
movq %rdx,TF_RDX(%rsp)
movq %rcx,TF_RCX(%rsp)
movq %r11,TF_R11(%rsp)
SAVE_SEGS
movq PCPU(CURPCB),%r11
andl $~PCB_FULL_IRET,PCB_FLAGS(%r11)
@@ -1439,6 +1439,7 @@ user_fred_syscall:
movq %r9,TF_R9(%rsp)
movq %rbx,TF_RBX(%rsp)
movq %rbp,TF_RBP(%rsp)
movq %r10,TF_RCX(%rsp)
movq %r12,TF_R12(%rsp)
movq %r13,TF_R13(%rsp)
movq %r14,TF_R14(%rsp)
@@ -1462,10 +1463,11 @@ user_fred_syscall:
movq TF_RSI(%rsp),%rsi
movq TF_RDX(%rsp),%rdx
movq TF_RAX(%rsp),%rax
movq TF_RIP(%rsp),%rcx
movq TF_RFLAGS(%rsp),%r11
xorl %r8d,%r8d
xorl %r9d,%r9d
xorl %r10d,%r10d
xorl %r11d,%r11d
addq $TF_ERR,%rsp
.globl fred_syscall_eretu
fred_syscall_eretu:
@@ -1648,10 +1650,10 @@ fred_events_handlers:
movq %rsi,TF_RSI(%rsp)
movl TF_FRED_EVINFO2(%rsp),%edi
movl %edi,%eax
andl $TF_FRED_EVINFO2_TYPEMASK,%edi
cmpl $TF_FRED_EVINFO2_TYPE_SYSCALL,%edi
je user_fred_syscall
jmp user_fred_non_syscall
andl $TF_FRED_EVINFO2_SYSCALLMASK,%edi
cmpl $TF_FRED_EVINFO2_SYSCALLVAL,%edi
jne user_fred_non_syscall
jmp user_fred_syscall
. = fred_events_handlers + 256
subq $TF_ERR,%rsp
+6
View File
@@ -190,9 +190,15 @@ ASSYM(TF_FRED_EVINFO2, offsetof(struct trapframe, tf_fred_evinfo2));
ASSYM(TF_FLAGS, offsetof(struct trapframe, tf_flags));
ASSYM(TF_SIZE, sizeof(struct trapframe));
ASSYM(TF_HASSEGS, TF_HASSEGS);
ASSYM(TF_FRED_EVINFO2_VECMASK, TF_FRED_EVINFO2_VECMASK);
ASSYM(TF_FRED_EVINFO2_VEC_SYSCALL, TF_FRED_EVINFO2_VEC_SYSCALL);
ASSYM(TF_FRED_EVINFO2_SYSCALLMASK, TF_FRED_EVINFO2_TYPEMASK |
TF_FRED_EVINFO2_VECMASK | TF_FRED_EVINFO2_LM);
ASSYM(TF_FRED_EVINFO2_TYPE_EXC, TF_FRED_EVINFO2_TYPE_EXC);
ASSYM(TF_FRED_EVINFO2_TYPE_SYSCALL, TF_FRED_EVINFO2_TYPE_SYSCALL);
ASSYM(TF_FRED_EVINFO2_TYPEMASK, TF_FRED_EVINFO2_TYPEMASK);
ASSYM(TF_FRED_EVINFO2_SYSCALLVAL, TF_FRED_EVINFO2_TYPE_SYSCALL |
TF_FRED_EVINFO2_VEC_SYSCALL | TF_FRED_EVINFO2_LM);
ASSYM(TF_FRED_EVINFO2_INSTLENMASK, TF_FRED_EVINFO2_INSTLENMASK);
ASSYM(TF_FRED_EVINFO2_INSTLENSHIFT, TF_FRED_EVINFO2_INSTLENSHIFT);
+3 -3
View File
@@ -451,14 +451,14 @@ amd64_cpu_init_fred(void)
/*
* With FRED, there is no need for workarounds requiring
* dedicated stack for #DB. Also, there is no need to have
* separate stacks for #NM and #MC, because CSL rules ensure
* separate stacks for NMI and #MC, because CSL rules ensure
* that interrupted frame is safe even if NMI was interrupted
* by machine check or vice versa.
*
* Still, we need to provide a stack for events that can occur
* with the interrupts disabled, to avoid caring about the
* ordering of the context update in cpu_switch.S. Use CSL 1
* for #NM and #MC.
* for NMI and #MC.
*
* Since double fault handler is used to handle stack
* overflow, it gets the dedicated stack, of the highest used
@@ -467,7 +467,7 @@ amd64_cpu_init_fred(void)
* CSL 3 is unused, and we have some space to re-arrange this
* if a need in the future appears.
*/
wrmsr(MSR_FRED_STKLVLS, (1ul << (IDT_NM * 2)) |
wrmsr(MSR_FRED_STKLVLS, (1ul << (IDT_NMI * 2)) |
(1ul << (IDT_MC * 2)) | (2ul << (IDT_DF * 2)));
wrmsr(MSR_FRED_RSP3, 0);
load_cr4(rcr4() | CR4_FRED);
+12 -4
View File
@@ -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);
}
+27 -7
View File
@@ -1573,6 +1573,24 @@ fred_inst_len(const struct trapframe_fred *frame)
TF_FRED_EVINFO2_INSTLENSHIFT);
}
/*
* Reaction to userspace having no permissions to generate the event.
* Report T_PROTFLT and rewind %rip back to emulate fault instead of
* trap.
*/
static void
trap_fred_u_noperm(struct trapframe_fred *frame, ksiginfo_t *ksi)
{
frame->tf_idt.tf_rip -= fred_inst_len(frame);
frame->tf_idt.tf_addr = 0;
frame->tf_idt.tf_trapno = T_PROTFLT;
ksiginfo_init_trap(ksi);
ksi->ksi_signo = SIGBUS;
ksi->ksi_code = BUS_OBJERR;
ksi->ksi_trapno = T_PROTFLT;
ksi->ksi_addr = (void *)frame->tf_idt.tf_rip;
}
int fred_verbose_events;
void trap_fred_u(struct trapframe_fred *frame);
@@ -1648,12 +1666,9 @@ trap_fred_u(struct trapframe_fred *frame)
break;
}
#endif
frame->tf_idt.tf_trapno = vec;
ksiginfo_init_trap(&ksi);
ksi.ksi_signo = SIGBUS;
ksi.ksi_code = BUS_OBJERR;
ksi.ksi_trapno = frame->tf_idt.tf_trapno;
ksi.ksi_addr = (void *)frame->tf_idt.tf_rip;
trap_fred_u_noperm(frame, &ksi);
/* error code: gate selector from IDT */
frame->tf_idt.tf_err = (vec * 8) | 2;
do_trapsig = true;
break;
case TF_FRED_EVINFO2_TYPE_SYSCALL:
@@ -1665,7 +1680,8 @@ trap_fred_u(struct trapframe_fred *frame)
amd64_syscall(td, (frame->tf_idt.tf_rflags & PSL_T) !=
0);
} else {
/* SYSENTER returns without action */
trap_fred_u_noperm(frame, &ksi);
do_trapsig = true;
}
break;
default:
@@ -1815,6 +1831,10 @@ trap_fred_handle_k_exc(struct thread *td, struct trapframe_fred *frame,
case IDT_MF:
break;
case IDT_AC:
if (curpcb->pcb_onfault != NULL) {
frame->tf_idt.tf_rip = (long)curpcb->pcb_onfault;
return;
}
break;
case IDT_MC:
mca_intr();
+3
View File
@@ -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));
+3
View File
@@ -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));
+8 -1
View File
@@ -160,7 +160,14 @@ dsp_destroy_dev(device_t dev)
struct snddev_info *d;
d = device_get_softc(dev);
destroy_dev(d->dsp_dev);
/*
* The cdev may not exist if the driver failed before or during
* pcm_register().
*/
if (d->dsp_dev != NULL) {
destroy_dev(d->dsp_dev);
d->dsp_dev = NULL;
}
}
static int
+6 -4
View File
@@ -428,8 +428,6 @@ pcm_register(device_t dev, char *str)
vchan_initsys(dev);
feeder_eq_initsys(dev);
sndstat_register(dev, SNDST_TYPE_PCM, d->status);
err = dsp_make_dev(dev);
if (err)
return (err);
@@ -441,6 +439,9 @@ pcm_register(device_t dev, char *str)
}
}
/* Publish only once registration really has finished properly. */
sndstat_register(dev, SNDST_TYPE_PCM, d->status);
bus_topo_lock();
if (snd_unit_auto < 0)
snd_unit_auto = (snd_unit < 0) ? 1 : 0;
@@ -463,8 +464,8 @@ pcm_unregister(device_t dev)
d = device_get_softc(dev);
if (!PCM_REGISTERED(d)) {
device_printf(dev, "unregister: device not configured\n");
if (!PCM_ALIVE(d)) {
device_printf(dev, "unregister: device not initialized\n");
return (0);
}
@@ -496,6 +497,7 @@ pcm_unregister(device_t dev)
cv_destroy(&d->cv);
mtx_destroy(&d->lock);
d->dev = NULL;
bus_topo_lock();
if (snd_unit == device_get_unit(dev)) {
+2 -2
View File
@@ -122,8 +122,8 @@ struct snd_mixer;
"\015PVCHANS" \
"\016RVCHANS"
#define PCM_REGISTERED(x) \
((x) != NULL && ((x)->flags & SD_F_REGISTERED))
#define PCM_ALIVE(x) ((x) != NULL && (x)->dev != NULL)
#define PCM_REGISTERED(x) (PCM_ALIVE(x) && ((x)->flags & SD_F_REGISTERED))
#define PCM_MAXCHANS 10000
#define PCM_CHANCOUNT(d) \
+3
View File
@@ -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;
+4 -1
View File
@@ -32,6 +32,7 @@
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/module.h>
#include <sys/msan.h>
#include <sys/sglist.h>
#include <sys/queue.h>
#include <sys/bus.h>
@@ -210,6 +211,7 @@ vt9p_intr_complete(void *xsc)
struct vt9p_softc *chan;
struct virtqueue *vq;
struct p9_req_t *curreq;
uint32_t len;
chan = (struct vt9p_softc *)xsc;
vq = chan->vt9p_vq;
@@ -218,8 +220,9 @@ vt9p_intr_complete(void *xsc)
VT9P_LOCK(chan);
again:
while ((curreq = virtqueue_dequeue(vq, NULL)) != NULL) {
while ((curreq = virtqueue_dequeue(vq, &len)) != NULL) {
curreq->rc.tag = curreq->tc.tag;
kmsan_mark(curreq->rc.sdata, len, KMSAN_STATE_INITED);
wakeup_one(curreq);
}
if (virtqueue_enable_intr(vq) != 0) {
+3
View File
@@ -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 *);
@@ -2971,6 +2972,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);
+9 -10
View File
@@ -54,11 +54,11 @@ class TestIGMP(VnetTestTemplate):
packets = self.sp.sniff(iface=ifname, timeout=5)
for r in packets:
r.show()
igmp = r.getlayer(self.sc.igmp.IGMP)
igmp = r.getlayer(self.sl.igmp.IGMP)
if not igmp:
continue
igmp.show()
if not igmp.gaddr == "230.0.0.1":
if getattr(igmp, 'gaddr', '0.0.0.0') != "230.0.0.1":
continue
found = True
return found
@@ -69,33 +69,32 @@ class TestIGMP(VnetTestTemplate):
"""Verify that we allow IGMP packets with IP options"""
ifname = self.vnet.iface_alias_map["if1"].name
# Import in the correct vnet, so at to not confuse Scapy
# Import in the correct vnet, so as to not confuse Scapy
import scapy.all as sp
import scapy.contrib as sc
import scapy.contrib.igmp
import scapy.layers as sl
self.sp = sp
self.sc = sc
self.sl = sl
# We allow IGMP packets with the router alert option
pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=1,
options=[sp.IPOption_Router_Alert()]) \
/ sc.igmp.IGMP(type=0x11, mrcode=1)
/ sl.igmp.IGMP(type=0x11, mrcode=1)
assert self.find_igmp_reply(pkt, ifname)
# But not with other options
pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=1,
options=[sp.IPOption_NOP()]) \
/ sc.igmp.IGMP(type=0x11, mrcode=1)
/ sl.igmp.IGMP(type=0x11, mrcode=1)
assert not self.find_igmp_reply(pkt, ifname)
# Or with the wrong TTL
pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=2,
options=[sp.IPOption_Router_Alert()]) \
/ sc.igmp.IGMP(type=0x11, mrcode=1)
/ sl.igmp.IGMP(type=0x11, mrcode=1)
assert not self.find_igmp_reply(pkt, ifname)
# Or with the wrong destination address
pkt = sp.IP(dst="224.0.0.2%%%s" % ifname, ttl=2,
options=[sp.IPOption_Router_Alert()]) \
/ sc.igmp.IGMP(type=0x11, mrcode=1)
/ sl.igmp.IGMP(type=0x11, mrcode=1)
assert not self.find_igmp_reply(pkt, ifname)
+2 -6
View File
@@ -40,9 +40,7 @@ ATF_TC_BODY(mmap_offset_overflow, tc)
buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, off);
ATF_REQUIRE_MSG(buf == MAP_FAILED, FMT_ERR("mmap"));
munmap(buf, len);
close(fd);
ATF_REQUIRE(close(fd) == 0);
}
/*
@@ -124,9 +122,7 @@ ATF_TC_BODY(mmap_reject_prot_exec, tc)
fd, 0);
ATF_REQUIRE_MSG(buf == MAP_FAILED, FMT_ERR("mmap"));
munmap(buf, len);
close(fd);
ATF_REQUIRE(close(fd) == 0);
}
/*
+5 -5
View File
@@ -98,7 +98,7 @@ ATF_TC_BODY(poll_kqueue, tc)
ATF_REQUIRE_MSG(read(fd, buf, sizeof(buf)) > 0, FMT_ERR("read"));
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
close(kq);
ATF_REQUIRE(close(kq) == 0);
kq = kqueue();
ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
@@ -113,9 +113,9 @@ ATF_TC_BODY(poll_kqueue, tc)
ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) > 0, FMT_ERR("write"));
EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
close(kq);
ATF_REQUIRE(close(kq) == 0);
close(fd);
ATF_REQUIRE(close(fd) == 0);
}
ATF_TC(poll_poll);
@@ -154,7 +154,7 @@ ATF_TC_BODY(poll_poll, tc)
wr = true;
}
}
close(fd);
ATF_REQUIRE(close(fd) == 0);
}
ATF_TC(poll_select);
@@ -192,7 +192,7 @@ ATF_TC_BODY(poll_select, tc)
wr = true;
}
}
close(fd);
ATF_REQUIRE(close(fd) == 0);
}
ATF_TP_ADD_TCS(tp)
+2 -2
View File
@@ -196,7 +196,7 @@ ATF_TC_BODY(sndstat_nv, tc)
free(arg.buf);
nvlist_destroy(nvl);
close(fd);
ATF_REQUIRE(close(fd) == 0);
}
#define UDEV_PROVIDER "sndstat_udev"
@@ -374,7 +374,7 @@ ATF_TC_BODY(sndstat_udev, tc)
free(arg.buf);
nvlist_destroy(nvl);
close(fd);
ATF_REQUIRE(close(fd) == 0);
}
ATF_TP_ADD_TCS(tp)