mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
Compare commits
50
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58066db597 | ||
|
|
5096328dd7 | ||
|
|
087b246271 | ||
|
|
e893ec49af | ||
|
|
13bf8945c9 | ||
|
|
183076d244 | ||
|
|
d3ee218868 | ||
|
|
1d75ce8356 | ||
|
|
21576f6396 | ||
|
|
7739dab974 | ||
|
|
6000de0966 | ||
|
|
abb0a18b69 | ||
|
|
a667c04946 | ||
|
|
b3f0e55578 | ||
|
|
0042987920 | ||
|
|
98e8cb3d94 | ||
|
|
29fbeb5c59 | ||
|
|
3aa9be7e33 | ||
|
|
a8d0ba4833 | ||
|
|
73da0e55aa | ||
|
|
faf94e22a3 | ||
|
|
27777283da | ||
|
|
e381992365 | ||
|
|
700ff8f05f | ||
|
|
3b8f0ffc0f | ||
|
|
2006e3634b | ||
|
|
7bcf0d3320 | ||
|
|
7847d5e56c | ||
|
|
eb7bf0d071 | ||
|
|
0ebe6df086 | ||
|
|
9b945635c1 | ||
|
|
9c67287ccf | ||
|
|
6a7bac2ae7 | ||
|
|
7d3a0370c8 | ||
|
|
abf370e400 | ||
|
|
d5c1fa0ec0 | ||
|
|
e664cd1dc5 | ||
|
|
7088bf662d | ||
|
|
140f361aa6 | ||
|
|
1b30c5d3a5 | ||
|
|
8807350405 | ||
|
|
246e27fa98 | ||
|
|
6a0215b2e3 | ||
|
|
30b27afe3b | ||
|
|
751c889691 | ||
|
|
4bf6ca0e71 | ||
|
|
a87a597313 | ||
|
|
bd3aa40e0a | ||
|
|
9badd542e7 | ||
|
|
e192230d0d |
No files matched your search
@@ -12,6 +12,30 @@ Items affecting the ports and packages system can be found in
|
||||
/usr/ports/UPDATING. Please read that file before updating system packages
|
||||
and/or ports.
|
||||
|
||||
20240917:
|
||||
13.4-RELEASE.
|
||||
|
||||
20240904:
|
||||
13.4-RC2-p1 SA-24:09.libnv
|
||||
SA-24:11.ctl
|
||||
SA-24:12.bhyve
|
||||
SA-24:14.umtx
|
||||
|
||||
Multiple vulnerabilities in libnv [SA-24:09.libnv]
|
||||
|
||||
Multiple issues in ctl(4) CAM Target Layer [SA-24:11.ctl]
|
||||
|
||||
bhyve(8) privileged guest escape via USB controller [SA-24:12.bhyve]
|
||||
|
||||
umtx Kernel panic or Use-After-Free [SA-24:14.umtx]
|
||||
|
||||
20240419:
|
||||
Clang, llvm, lld, lldb, compiler-rt, libc++, libunwind and openmp have
|
||||
been upgraded to 18.1.6. It is important that you run `make delete-old`
|
||||
as described in the COMMON ITEMS section, otherwise several libc++
|
||||
headers that are obsolete and need to be removed can cause compilation
|
||||
errors in C++ programs.
|
||||
|
||||
20240218:
|
||||
MFC of 713db49d06de changed 'struct ieee80211vap' internals in net80211.
|
||||
Given we do not have enough spares and the struct is allocated by
|
||||
|
||||
@@ -46,7 +46,7 @@ class X86CompressEVEXTablesEmitter {
|
||||
|
||||
typedef std::pair<const CodeGenInstruction *, const CodeGenInstruction *>
|
||||
Entry;
|
||||
typedef std::map<const Record *, std::vector<const CodeGenInstruction *>>
|
||||
typedef std::map<StringRef, std::vector<const CodeGenInstruction *>>
|
||||
PredicateInstMap;
|
||||
|
||||
std::vector<Entry> Table;
|
||||
@@ -89,7 +89,7 @@ void X86CompressEVEXTablesEmitter::printCheckPredicate(
|
||||
for (const auto &[Key, Val] : PredicateInsts) {
|
||||
for (const auto &Inst : Val)
|
||||
OS << " case X86::" << Inst->TheDef->getName() << ":\n";
|
||||
OS << " return " << Key->getValueAsString("CondString") << ";\n";
|
||||
OS << " return " << Key << ";\n";
|
||||
}
|
||||
|
||||
OS << " }\n";
|
||||
@@ -226,7 +226,7 @@ void X86CompressEVEXTablesEmitter::run(raw_ostream &OS) {
|
||||
Name == "HasAVXIFMA";
|
||||
});
|
||||
if(It!= Predicates.end())
|
||||
PredicateInsts[*It].push_back(NewInst);
|
||||
PredicateInsts[(*It)->getValueAsString("CondString")].push_back(NewInst);
|
||||
}
|
||||
|
||||
printTable(Table, OS);
|
||||
|
||||
@@ -44,4 +44,4 @@
|
||||
# ProxyCommand ssh -q -W %h:%p gateway.example.com
|
||||
# RekeyLimit 1G 1h
|
||||
# UserKnownHostsFile ~/.ssh/known_hosts.d/%k
|
||||
# VersionAddendum FreeBSD-20240318
|
||||
# VersionAddendum FreeBSD-20240806
|
||||
@@ -2137,7 +2137,7 @@ in
|
||||
Specifies a string to append to the regular version string to identify
|
||||
OS- or site-specific modifications.
|
||||
The default is
|
||||
.Dq FreeBSD-20240318 .
|
||||
.Dq FreeBSD-20240806 .
|
||||
The value
|
||||
.Cm none
|
||||
may be used to disable this.
|
||||
|
||||
@@ -377,8 +377,6 @@ grace_alarm_handler(int sig)
|
||||
kill(0, SIGTERM);
|
||||
}
|
||||
|
||||
BLACKLIST_NOTIFY(the_active_state, BLACKLIST_AUTH_FAIL, "ssh");
|
||||
|
||||
/* Log error and exit. */
|
||||
sigdie("Timeout before authentication for %s port %d",
|
||||
ssh_remote_ipaddr(the_active_state),
|
||||
|
||||
@@ -105,7 +105,7 @@ AuthorizedKeysFile .ssh/authorized_keys
|
||||
#PermitTunnel no
|
||||
#ChrootDirectory none
|
||||
#UseBlacklist no
|
||||
#VersionAddendum FreeBSD-20240318
|
||||
#VersionAddendum FreeBSD-20240806
|
||||
|
||||
# no default banner path
|
||||
#Banner none
|
||||
|
||||
@@ -1947,7 +1947,7 @@ The default is
|
||||
Optionally specifies additional text to append to the SSH protocol banner
|
||||
sent by the server upon connection.
|
||||
The default is
|
||||
.Qq FreeBSD-20240318 .
|
||||
.Qq FreeBSD-20240806 .
|
||||
The value
|
||||
.Cm none
|
||||
may be used to disable this.
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
#define SSH_PORTABLE "p1"
|
||||
#define SSH_RELEASE SSH_VERSION SSH_PORTABLE
|
||||
|
||||
#define SSH_VERSION_FREEBSD "FreeBSD-20240701"
|
||||
#define SSH_VERSION_FREEBSD "FreeBSD-20240806"
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Execute the "real" sendmail program, named /usr/libexec/sendmail/sendmail
|
||||
#
|
||||
# If dma(8) is installed, an example mailer.conf that uses dma(8) instead can
|
||||
# If dma(8) is installed, an example mailer.conf that uses dma(8) instead
|
||||
# can be found in /usr/share/examples/dma.
|
||||
#
|
||||
sendmail /usr/libexec/sendmail/sendmail
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
.4byte NT_FREEBSD_ABI_TAG
|
||||
1: .asciz NOTE_FREEBSD_VENDOR
|
||||
2: .p2align 2
|
||||
3: .4byte __FreeBSD_version
|
||||
3: .4byte 1304000
|
||||
4:
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -1,5 +1,5 @@
|
||||
release: {
|
||||
url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
|
||||
url: "pkg+http://pkg.FreeBSD.org/${ABI}/release_4",
|
||||
mirror_type: "srv",
|
||||
signature_type: "fingerprints",
|
||||
fingerprints: "/usr/share/keys/pkg",
|
||||
|
||||
@@ -12,27 +12,26 @@ export ROOTDIR="$PWD/dvd"
|
||||
export PKGCMD="/usr/sbin/pkg -d --rootdir ${ROOTDIR}"
|
||||
export PORTSDIR="${PORTSDIR:-/usr/ports}"
|
||||
|
||||
_DVD_PACKAGES="archivers/unzip
|
||||
devel/git
|
||||
emulators/linux_base-c7
|
||||
_DVD_PACKAGES="devel/git@lite
|
||||
graphics/drm-kmod
|
||||
graphics/drm-510-kmod
|
||||
misc/freebsd-doc-all
|
||||
net/mpd5
|
||||
net/rsync
|
||||
ports-mgmt/pkg
|
||||
ports-mgmt/portmaster
|
||||
shells/bash
|
||||
shells/zsh
|
||||
security/sudo
|
||||
sysutils/screen
|
||||
sysutils/seatd
|
||||
sysutils/tmux
|
||||
www/firefox
|
||||
www/links
|
||||
x11-drivers/xf86-video-vmware
|
||||
x11/gnome
|
||||
x11/kde5
|
||||
x11/xorg"
|
||||
x11/sddm
|
||||
x11/xorg
|
||||
x11-wm/sway"
|
||||
|
||||
# If NOPORTS is set for the release, do not attempt to build pkg(8).
|
||||
if [ ! -f ${PORTSDIR}/Makefile ]; then
|
||||
@@ -59,10 +58,10 @@ fi
|
||||
# Ensure the ports listed in _DVD_PACKAGES exist to sanitize the
|
||||
# final list.
|
||||
for _P in ${_DVD_PACKAGES}; do
|
||||
if [ -d "${PORTSDIR}/${_P}" ]; then
|
||||
if [ -d "${PORTSDIR}/${_P%%@*}" ]; then
|
||||
DVD_PACKAGES="${DVD_PACKAGES} ${_P}"
|
||||
else
|
||||
echo "*** Skipping nonexistent port: ${_P}"
|
||||
echo "*** Skipping nonexistent port: ${_P%%@*}"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
@@ -105,6 +105,11 @@ LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -pie
|
||||
LDFLAGS+= -Wl,--no-dynamic-linker
|
||||
.endif
|
||||
|
||||
# When lld is using multiple threads, which it does by default, it can
|
||||
# result in non-reproducible output with the custom linker script. Work
|
||||
# around this by disabling threading.
|
||||
LDFLAGS.lld+= -Wl,--threads=1
|
||||
|
||||
CLEANFILES+= ${LOADER}.efi
|
||||
|
||||
${LOADER}.efi: ${PROG}
|
||||
|
||||
+117
-22
@@ -30,7 +30,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd September 4, 2022
|
||||
.Dd September 3, 2024
|
||||
.Dt LOADER.EFI 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -345,43 +345,138 @@ The default location for the ESP mount point is documented in
|
||||
The following examples shows how to install a new
|
||||
.Nm
|
||||
on the ESP.
|
||||
The exact placement is complicated due to the diversity of
|
||||
installations, setups and situations.
|
||||
In this section, paths that are all lower case are Unix paths.
|
||||
Paths that are all upper case are relative to the ESP mount point,
|
||||
though they may appear as lower case on your system because the
|
||||
FAT filesystem of the ESP is case insensitive.
|
||||
.Pp
|
||||
First, find the partition of type
|
||||
Locate the ESP, which has its own partition type of
|
||||
.Dq efi :
|
||||
.Bd -literal -offset indent
|
||||
# gpart list | grep -Ew '(Name|efi)'
|
||||
1. Name: nvd0p1
|
||||
type: efi
|
||||
2. Name: nvd0p2
|
||||
3. Name: nvd0p3
|
||||
4. Name: nvd0p4
|
||||
1. Name: nvd0
|
||||
# gpart show nda0
|
||||
=> 40 7501476448 nda0 GPT (3.5T)
|
||||
40 614400 1 efi (300M)
|
||||
614440 7500862048 2 freebsd-zfs (3.5T)
|
||||
.Ed
|
||||
.Pp
|
||||
The name of the ESP on this system is
|
||||
.Pa nvd0p1 .
|
||||
.Pa nda0p1 .
|
||||
By default, this will be mounted on
|
||||
.Pa /boot/efi .
|
||||
To check:
|
||||
.Bd -literal -offset indent
|
||||
# mount | grep nda0p1
|
||||
/dev/nda0p1 on /boot/efi (msdosfs, local)
|
||||
.Ed
|
||||
If it's not mounted, you will need to mount it:
|
||||
.Bd -literal -offset indent
|
||||
# mount -t msdosfs /dev/nda0p1 /boot/efi
|
||||
.Ed
|
||||
.Pp
|
||||
Second, let's mount the ESP, copy
|
||||
.Nm
|
||||
to the special location reserved for
|
||||
.Fx
|
||||
EFI loaders, and unmount once finished:
|
||||
.Xr efibootmgr 8
|
||||
reports what we booted from.
|
||||
.Bd -literal -offset indent
|
||||
# efibootmgr -v
|
||||
Boot to FW : false
|
||||
BootCurrent: 0001
|
||||
Timeout : 2 seconds
|
||||
BootOrder : 0000, 0001, 0003, 0004, 0005, 0006, 0001, 0008, 000A, 000B, 000C, 000E, 0007
|
||||
...
|
||||
+Boot0001* FreeBSD ZPOOL HD(1,GPT,b5d0f86b-265d-1e1b-18aa-0ed55e1e73bd,0x28,0x96000)/File(\EFI\FREEBSD\LOADER.EFI)
|
||||
nda0p1:/EFI/FREEBSD/LOADER.EFI /boot/efi//EFI/FREEBSD/LOADER.EFI
|
||||
...
|
||||
.Ed
|
||||
Often there are several options, depending on the BIOS.
|
||||
The entry that we booted with is marked with a
|
||||
.Sq +
|
||||
at the start of the line, as shown above.
|
||||
So in this case, this firmware is using
|
||||
.Pa /EFI/FREEBSD/LOADER.EFI
|
||||
from the ESP.
|
||||
Often times it will be the UEFI
|
||||
.Dq default
|
||||
loader, which varies by architecture.
|
||||
.Bl -column -offset indent "Architecture" "Default Path"
|
||||
.It Sy Architecture Ta Sy Default Path
|
||||
.It amd64 Ta Pa /EFI/BOOT/BOOTX64.EFI
|
||||
.It arm Ta Pa /EFI/BOOT/BOOTARM.EFI
|
||||
.It arm64 Ta Pa /EFI/BOOT/BOOTAA64.EFI
|
||||
.It i386 Ta Pa /EFI/BOOT/BOOTIA32.EFI
|
||||
.It riscv Ta Pa /EFI/BOOT/BOOTRISCV64.EFI
|
||||
.El
|
||||
However, care must be taken: some multiple-boot environments rely on a special
|
||||
.Pa bootXXX.efi
|
||||
to function.
|
||||
Before updating a
|
||||
.Pa bootXXX.efi
|
||||
file, make sure it is the FreeBSD boot loader before updating it:
|
||||
.Bd -literal -offset indent
|
||||
# strings /boot/efi/EFI/BOOT/BOOTX64.EFI | grep FreeBSD | grep EFI
|
||||
FreeBSD/amd64 EFI loader, Revision 3.0
|
||||
.Ed
|
||||
.Pp
|
||||
.Xr bsdinstall 8
|
||||
copies
|
||||
.Pa loader.efi
|
||||
to the default name if there wasn't one there before.
|
||||
Check to see if they are copies before updating (with X64 substituted using the
|
||||
above table):
|
||||
.Bd -literal -offset indent
|
||||
# cmp /boot/efi/EFI/FREEBSD/LOADER.EFI /boot/efi/EFI/BOOT/BOOOTX64.EFI
|
||||
.Ed
|
||||
Copy the loader:
|
||||
.Bd -literal -offset indent
|
||||
# cp /boot/loader.efi /boot/efi/EFI/FREEBSD/LOADER.EFI
|
||||
.Ed
|
||||
replacing the all caps part of the example with the proper path.
|
||||
.Pp
|
||||
If ESP path was
|
||||
.Pa /FREEBSD/LOADER.EFI
|
||||
and LOADER.EFI and BOOTX64.EFI were identical in the cmp step,
|
||||
copy the loader to the default location:
|
||||
.Bd -literal -offset indent
|
||||
# cp /boot/loader.efi /boot/efi/EFI/BOOT/BOOTX64.EFI
|
||||
.Ed
|
||||
.Pp
|
||||
Finally, if you mounted the ESP, you may wish to unmount it.
|
||||
.Bd -literal -offset indent
|
||||
# mount_msdosfs /dev/nvd0p1 /boot/efi
|
||||
# cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
|
||||
# umount /boot/efi
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr loader 8 ,
|
||||
.Xr uefi 8
|
||||
.Sh BUGS
|
||||
Systems that do not have a
|
||||
.Dv ConOut
|
||||
variable set are not conformant with the standard, and likely have unexpected
|
||||
results.
|
||||
.Pp
|
||||
Non-x86 serial console handling is even more confusing and less well documented.
|
||||
.Pp
|
||||
Sometimes when the serial port speed isn't set, 9600 is used.
|
||||
Other times the result is typically 115200 since the speed remains unchanged
|
||||
from the default.
|
||||
.Pp
|
||||
U-Boot implements a subset of the UEFI standard.
|
||||
Some versions do not support fetching loader variables, so
|
||||
.Pa efibootmgr
|
||||
may not work.
|
||||
In addition,
|
||||
.Pa efibootmgr
|
||||
is not supported on armv7 or riscv.
|
||||
In these instances, the user has to understand what was booted to update
|
||||
it properly (and in most cases, it will be the FreeBSD path and the UEFI default
|
||||
so just copy loader.efi there if there are loaders there).
|
||||
Typically in these embedded situations, there is only one .efi file (loader.efi
|
||||
or a copy of loader.efi).
|
||||
The path to this file is typically the default removable path above.
|
||||
.Pp
|
||||
Managing booting multiple OSes on UEFI varies greatly, so extra caution when
|
||||
updating the UEFI default loader.
|
||||
.Pp
|
||||
The old, now obsolete, boot1.efi was installed as bootx64.efi in
|
||||
.Fx 10
|
||||
and earlier.
|
||||
Since it was quite limited in functionality, we created very small
|
||||
ESPs by default.
|
||||
A modern loader.efi will not fit.
|
||||
However, if the old boot1.efi still works, there's no need to update
|
||||
it since it will chain boot /boot/loader.efi from a copy that
|
||||
make installworld updates.
|
||||
+22
-26
@@ -5633,7 +5633,7 @@ ctl_read_buffer(struct ctl_scsiio *ctsio)
|
||||
} else {
|
||||
if (lun->write_buffer == NULL) {
|
||||
lun->write_buffer = malloc(CTL_WRITE_BUFFER_SIZE,
|
||||
M_CTL, M_WAITOK);
|
||||
M_CTL, M_WAITOK | M_ZERO);
|
||||
}
|
||||
ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
|
||||
}
|
||||
@@ -5672,21 +5672,24 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
if (lun->write_buffer == NULL) {
|
||||
lun->write_buffer = malloc(CTL_WRITE_BUFFER_SIZE,
|
||||
M_CTL, M_WAITOK | M_ZERO);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've got a kernel request that hasn't been malloced yet,
|
||||
* malloc it and tell the caller the data buffer is here.
|
||||
* If this kernel request hasn't started yet, initialize the data
|
||||
* buffer to the correct region of the LUN's write buffer. Note that
|
||||
* this doesn't set CTL_FLAG_ALLOCATED since this points into a
|
||||
* persistent buffer belonging to the LUN rather than a buffer
|
||||
* dedicated to this request.
|
||||
*/
|
||||
if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
|
||||
if (lun->write_buffer == NULL) {
|
||||
lun->write_buffer = malloc(CTL_WRITE_BUFFER_SIZE,
|
||||
M_CTL, M_WAITOK);
|
||||
}
|
||||
if (ctsio->kern_data_ptr == NULL) {
|
||||
ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
|
||||
ctsio->kern_data_len = len;
|
||||
ctsio->kern_total_len = len;
|
||||
ctsio->kern_rel_offset = 0;
|
||||
ctsio->kern_sg_entries = 0;
|
||||
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
|
||||
ctsio->be_move_done = ctl_config_move_done;
|
||||
ctl_datamove((union ctl_io *)ctsio);
|
||||
|
||||
@@ -7510,20 +7513,19 @@ ctl_report_supported_opcodes(struct ctl_scsiio *ctsio)
|
||||
case RSO_OPTIONS_OC_SA:
|
||||
if ((ctl_cmd_table[opcode].flags & CTL_CMD_FLAG_SA5) == 0 ||
|
||||
service_action >= 32) {
|
||||
ctl_set_invalid_field(/*ctsio*/ ctsio,
|
||||
/*sks_valid*/ 1,
|
||||
/*command*/ 1,
|
||||
/*field*/ 2,
|
||||
/*bit_valid*/ 1,
|
||||
/*bit*/ 2);
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
goto invalid;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
total_len = sizeof(struct scsi_report_supported_opcodes_one) + 32;
|
||||
break;
|
||||
case RSO_OPTIONS_OC_ASA:
|
||||
if ((ctl_cmd_table[opcode].flags & CTL_CMD_FLAG_SA5) != 0 &&
|
||||
service_action >= 32) {
|
||||
goto invalid;
|
||||
}
|
||||
total_len = sizeof(struct scsi_report_supported_opcodes_one) + 32;
|
||||
break;
|
||||
default:
|
||||
invalid:
|
||||
ctl_set_invalid_field(/*ctsio*/ ctsio,
|
||||
/*sks_valid*/ 1,
|
||||
/*command*/ 1,
|
||||
@@ -9339,14 +9341,8 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
|
||||
sense_ptr = (struct scsi_sense_data *)ctsio->kern_data_ptr;
|
||||
ctsio->kern_sg_entries = 0;
|
||||
ctsio->kern_rel_offset = 0;
|
||||
|
||||
/*
|
||||
* struct scsi_sense_data, which is currently set to 256 bytes, is
|
||||
* larger than the largest allowed value for the length field in the
|
||||
* REQUEST SENSE CDB, which is 252 bytes as of SPC-4.
|
||||
*/
|
||||
ctsio->kern_data_len = cdb->length;
|
||||
ctsio->kern_total_len = cdb->length;
|
||||
ctsio->kern_data_len = ctsio->kern_total_len =
|
||||
MIN(cdb->length, sizeof(*sense_ptr));
|
||||
|
||||
/*
|
||||
* If we don't have a LUN, we don't have any pending sense.
|
||||
|
||||
@@ -410,6 +410,14 @@ struct ctl_lun {
|
||||
uint8_t pr_res_type;
|
||||
int prevent_count;
|
||||
uint32_t *prevent;
|
||||
|
||||
/*
|
||||
* The READ_BUFFER and WRITE_BUFFER commands permit access to a logical
|
||||
* data buffer associated with a LUN. Accesses to the data buffer do
|
||||
* not affect data stored on the storage medium. To support this,
|
||||
* allocate a buffer on first use that persists until the LUN is
|
||||
* destroyed.
|
||||
*/
|
||||
uint8_t *write_buffer;
|
||||
struct ctl_devid *lun_devid;
|
||||
TAILQ_HEAD(tpc_lists, tpc_list) tpc_lists;
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@
|
||||
|
||||
TYPE="FreeBSD"
|
||||
REVISION="13.4"
|
||||
BRANCH="PRERELEASE"
|
||||
BRANCH="RELEASE"
|
||||
if [ -n "${BRANCH_OVERRIDE}" ]; then
|
||||
BRANCH=${BRANCH_OVERRIDE}
|
||||
fi
|
||||
|
||||
@@ -986,6 +986,10 @@ nvpair_unpack_string_array(bool isbe __unused, nvpair_t *nvp,
|
||||
for (ii = 0; ii < nvp->nvp_nitems; ii++) {
|
||||
len = strnlen(tmp, size - 1) + 1;
|
||||
size -= len;
|
||||
if (tmp[len - 1] != '\0') {
|
||||
ERRNO_SET(EINVAL);
|
||||
return (NULL);
|
||||
}
|
||||
if (size < 0) {
|
||||
ERRNO_SET(EINVAL);
|
||||
return (NULL);
|
||||
@@ -997,7 +1001,7 @@ nvpair_unpack_string_array(bool isbe __unused, nvpair_t *nvp,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
value = nv_malloc(sizeof(*value) * nvp->nvp_nitems);
|
||||
value = nv_calloc(nvp->nvp_nitems, sizeof(*value));
|
||||
if (value == NULL)
|
||||
return (NULL);
|
||||
|
||||
@@ -1090,7 +1094,7 @@ nvpair_unpack_nvlist_array(bool isbe __unused, nvpair_t *nvp,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
value = nv_malloc(nvp->nvp_nitems * sizeof(*value));
|
||||
value = nv_calloc(nvp->nvp_nitems, sizeof(*value));
|
||||
if (value == NULL)
|
||||
return (NULL);
|
||||
|
||||
@@ -1328,10 +1332,10 @@ nvpair_create_bool_array(const char *name, const bool *value, size_t nitems)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
size = sizeof(value[0]) * nitems;
|
||||
data = nv_malloc(size);
|
||||
data = nv_calloc(nitems, sizeof(value[0]));
|
||||
if (data == NULL)
|
||||
return (NULL);
|
||||
size = sizeof(value[0]) * nitems;
|
||||
|
||||
memcpy(data, value, size);
|
||||
nvp = nvpair_allocv(name, NV_TYPE_BOOL_ARRAY, (uint64_t)(uintptr_t)data,
|
||||
@@ -1358,10 +1362,10 @@ nvpair_create_number_array(const char *name, const uint64_t *value,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
size = sizeof(value[0]) * nitems;
|
||||
data = nv_malloc(size);
|
||||
data = nv_calloc(nitems, sizeof(value[0]));
|
||||
if (data == NULL)
|
||||
return (NULL);
|
||||
size = sizeof(value[0]) * nitems;
|
||||
|
||||
memcpy(data, value, size);
|
||||
nvp = nvpair_allocv(name, NV_TYPE_NUMBER_ARRAY,
|
||||
@@ -1391,7 +1395,7 @@ nvpair_create_string_array(const char *name, const char * const *value,
|
||||
|
||||
nvp = NULL;
|
||||
datasize = 0;
|
||||
data = nv_malloc(sizeof(value[0]) * nitems);
|
||||
data = nv_calloc(nitems, sizeof(value[0]));
|
||||
if (data == NULL)
|
||||
return (NULL);
|
||||
|
||||
@@ -1438,7 +1442,7 @@ nvpair_create_nvlist_array(const char *name, const nvlist_t * const *value,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
nvls = nv_malloc(sizeof(value[0]) * nitems);
|
||||
nvls = nv_calloc(nitems, sizeof(value[0]));
|
||||
if (nvls == NULL)
|
||||
return (NULL);
|
||||
|
||||
@@ -1505,7 +1509,7 @@ nvpair_create_descriptor_array(const char *name, const int *value,
|
||||
|
||||
nvp = NULL;
|
||||
|
||||
fds = nv_malloc(sizeof(value[0]) * nitems);
|
||||
fds = nv_calloc(nitems, sizeof(value[0]));
|
||||
if (fds == NULL)
|
||||
return (NULL);
|
||||
for (ii = 0; ii < nitems; ii++) {
|
||||
|
||||
@@ -758,7 +758,7 @@ nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
|
||||
int *fds;
|
||||
|
||||
nitems = nvlist_ndescriptors(nvl);
|
||||
fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
|
||||
fds = nv_calloc(nitems + 1, sizeof(fds[0]));
|
||||
if (fds == NULL)
|
||||
return (NULL);
|
||||
if (nitems > 0)
|
||||
@@ -1029,6 +1029,10 @@ static bool
|
||||
nvlist_check_header(struct nvlist_header *nvlhdrp)
|
||||
{
|
||||
|
||||
if (nvlhdrp->nvlh_size > SIZE_MAX - sizeof(nvlhdrp)) {
|
||||
ERRNO_SET(EINVAL);
|
||||
return (false);
|
||||
}
|
||||
if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
|
||||
ERRNO_SET(EINVAL);
|
||||
return (false);
|
||||
@@ -1302,7 +1306,7 @@ nvlist_recv(int sock, int flags)
|
||||
goto out;
|
||||
|
||||
if (nfds > 0) {
|
||||
fds = nv_malloc(nfds * sizeof(fds[0]));
|
||||
fds = nv_calloc(nfds, sizeof(fds[0]));
|
||||
if (fds == NULL)
|
||||
goto out;
|
||||
if (fd_recv(sock, fds, nfds) == -1)
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630
|
||||
#define PCI_DEVICE_ID_AMD_19H_M10H_ROOT 0x14a4
|
||||
#define PCI_DEVICE_ID_AMD_19H_M60H_ROOT 0x14d8
|
||||
#define PCI_DEVICE_ID_AMD_19H_M70H_ROOT 0x14e8
|
||||
|
||||
struct pciid;
|
||||
struct amdsmn_softc {
|
||||
@@ -116,6 +117,12 @@ static const struct pciid {
|
||||
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
|
||||
.amdsmn_data_reg = F17H_SMN_DATA_REG,
|
||||
},
|
||||
{
|
||||
.amdsmn_vendorid = CPU_VENDOR_AMD,
|
||||
.amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M70H_ROOT,
|
||||
.amdsmn_addr_reg = F17H_SMN_ADDR_REG,
|
||||
.amdsmn_data_reg = F17H_SMN_DATA_REG,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -116,6 +116,7 @@ struct amdtemp_softc {
|
||||
#define DEVICEID_AMD_HOSTB17H_M60H_ROOT 0x1630
|
||||
#define DEVICEID_AMD_HOSTB19H_M10H_ROOT 0x14a4
|
||||
#define DEVICEID_AMD_HOSTB19H_M60H_ROOT 0x14d8
|
||||
#define DEVICEID_AMD_HOSTB19H_M70H_ROOT 0x14e8
|
||||
|
||||
static const struct amdtemp_product {
|
||||
uint16_t amdtemp_vendorid;
|
||||
@@ -142,6 +143,7 @@ static const struct amdtemp_product {
|
||||
{ VENDORID_AMD, DEVICEID_AMD_HOSTB17H_M60H_ROOT, false },
|
||||
{ VENDORID_AMD, DEVICEID_AMD_HOSTB19H_M10H_ROOT, false },
|
||||
{ VENDORID_AMD, DEVICEID_AMD_HOSTB19H_M60H_ROOT, false },
|
||||
{ VENDORID_AMD, DEVICEID_AMD_HOSTB19H_M70H_ROOT, false },
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -875,6 +877,7 @@ amdtemp_probe_ccd_sensors19h(device_t dev, uint32_t model)
|
||||
_Static_assert((int)NUM_CCDS >= 12, "");
|
||||
break;
|
||||
case 0x60 ... 0x6f: /* Zen4 Ryzen "Raphael" */
|
||||
case 0x70 ... 0x7f: /* Zen4 Ryzen "Phoenix" */
|
||||
sc->sc_temp_base = AMDTEMP_ZEN4_CCD_TMP_BASE;
|
||||
maxreg = 8;
|
||||
_Static_assert((int)NUM_CCDS >= 8, "");
|
||||
|
||||
+12
-13
@@ -1025,29 +1025,28 @@ cxgbe_nm_tx(struct adapter *sc, struct sge_nm_txq *nm_txq,
|
||||
nm_txq->pidx = 0;
|
||||
}
|
||||
|
||||
if (npkt == 0 && npkt_remaining == 0) {
|
||||
if (npkt + npkt_remaining == 0) {
|
||||
/* All done. */
|
||||
if (lazy_tx_credit_flush == 0) {
|
||||
if (lazy_tx_credit_flush == 0 ||
|
||||
NMIDXDIFF(nm_txq, equiqidx) >= nm_txq->sidx / 2) {
|
||||
wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ |
|
||||
F_FW_WR_EQUIQ);
|
||||
nm_txq->equeqidx = nm_txq->pidx;
|
||||
nm_txq->equiqidx = nm_txq->pidx;
|
||||
} else if (NMIDXDIFF(nm_txq, equeqidx) >= 64) {
|
||||
wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ);
|
||||
nm_txq->equeqidx = nm_txq->pidx;
|
||||
}
|
||||
ring_nm_txq_db(sc, nm_txq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NMIDXDIFF(nm_txq, equiqidx) >= nm_txq->sidx / 2) {
|
||||
wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ |
|
||||
F_FW_WR_EQUIQ);
|
||||
nm_txq->equeqidx = nm_txq->pidx;
|
||||
nm_txq->equiqidx = nm_txq->pidx;
|
||||
} else if (NMIDXDIFF(nm_txq, equeqidx) >= 64) {
|
||||
wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ);
|
||||
nm_txq->equeqidx = nm_txq->pidx;
|
||||
}
|
||||
if (NMIDXDIFF(nm_txq, dbidx) >= 2 * SGE_MAX_WR_NDESC)
|
||||
if (NMIDXDIFF(nm_txq, dbidx) >= 2 * SGE_MAX_WR_NDESC) {
|
||||
if (NMIDXDIFF(nm_txq, equeqidx) >= 64) {
|
||||
wr->equiq_to_len16 |= htobe32(F_FW_WR_EQUEQ);
|
||||
nm_txq->equeqidx = nm_txq->pidx;
|
||||
}
|
||||
ring_nm_txq_db(sc, nm_txq);
|
||||
}
|
||||
}
|
||||
|
||||
/* Will get called again. */
|
||||
|
||||
@@ -724,7 +724,9 @@ mountmsdosfs(struct vnode *odevvp, struct mount *mp)
|
||||
}
|
||||
}
|
||||
|
||||
clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv ;
|
||||
clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv;
|
||||
if (clusters >= (CLUST_RSRVD & pmp->pm_fatmask))
|
||||
clusters = CLUST_RSRVD & pmp->pm_fatmask;
|
||||
if (pmp->pm_maxcluster >= clusters) {
|
||||
#ifdef MSDOSFS_DEBUG
|
||||
printf("Warning: number of clusters (%ld) exceeds FAT "
|
||||
|
||||
@@ -585,7 +585,7 @@ ktrprocexec(struct proc *p)
|
||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||
|
||||
kiop = p->p_ktrioparms;
|
||||
if (kiop == NULL || priv_check_cred(kiop->cr, PRIV_DEBUG_DIFFCRED))
|
||||
if (kiop == NULL || priv_check_cred(kiop->cr, PRIV_DEBUG_DIFFCRED) == 0)
|
||||
return (NULL);
|
||||
|
||||
mtx_lock(&ktrace_mtx);
|
||||
|
||||
+92
-49
@@ -4293,8 +4293,7 @@ __umtx_op_sem2_wake(struct thread *td, struct _umtx_op_args *uap,
|
||||
#define USHM_OBJ_UMTX(o) \
|
||||
((struct umtx_shm_obj_list *)(&(o)->umtx_data))
|
||||
|
||||
#define USHMF_REG_LINKED 0x0001
|
||||
#define USHMF_OBJ_LINKED 0x0002
|
||||
#define USHMF_LINKED 0x0001
|
||||
struct umtx_shm_reg {
|
||||
TAILQ_ENTRY(umtx_shm_reg) ushm_reg_link;
|
||||
LIST_ENTRY(umtx_shm_reg) ushm_obj_link;
|
||||
@@ -4335,8 +4334,17 @@ umtx_shm_reg_delfree_tq(void *context __unused, int pending __unused)
|
||||
static struct task umtx_shm_reg_delfree_task =
|
||||
TASK_INITIALIZER(0, umtx_shm_reg_delfree_tq, NULL);
|
||||
|
||||
static struct umtx_shm_reg *
|
||||
umtx_shm_find_reg_locked(const struct umtx_key *key)
|
||||
/*
|
||||
* Returns 0 if a SHM with the passed key is found in the registry, in which
|
||||
* case it is returned through 'oreg'. Otherwise, returns an error among ESRCH
|
||||
* (no corresponding SHM; ESRCH was chosen for compatibility, ENOENT would have
|
||||
* been preferable) or EOVERFLOW (there is a corresponding SHM, but reference
|
||||
* count would overflow, so can't return it), in which case '*oreg' is left
|
||||
* unchanged.
|
||||
*/
|
||||
static int
|
||||
umtx_shm_find_reg_locked(const struct umtx_key *key,
|
||||
struct umtx_shm_reg **const oreg)
|
||||
{
|
||||
struct umtx_shm_reg *reg;
|
||||
struct umtx_shm_reg_head *reg_head;
|
||||
@@ -4352,26 +4360,38 @@ umtx_shm_find_reg_locked(const struct umtx_key *key)
|
||||
reg->ushm_key.info.shared.offset ==
|
||||
key->info.shared.offset) {
|
||||
KASSERT(reg->ushm_key.type == TYPE_SHM, ("TYPE_USHM"));
|
||||
KASSERT(reg->ushm_refcnt > 0,
|
||||
KASSERT(reg->ushm_refcnt != 0,
|
||||
("reg %p refcnt 0 onlist", reg));
|
||||
KASSERT((reg->ushm_flags & USHMF_REG_LINKED) != 0,
|
||||
KASSERT((reg->ushm_flags & USHMF_LINKED) != 0,
|
||||
("reg %p not linked", reg));
|
||||
/*
|
||||
* Don't let overflow happen, just deny a new reference
|
||||
* (this is additional protection against some reference
|
||||
* count leak, which is known not to be the case at the
|
||||
* time of this writing).
|
||||
*/
|
||||
if (__predict_false(reg->ushm_refcnt == UINT_MAX))
|
||||
return (EOVERFLOW);
|
||||
reg->ushm_refcnt++;
|
||||
return (reg);
|
||||
*oreg = reg;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
return (ESRCH);
|
||||
}
|
||||
|
||||
static struct umtx_shm_reg *
|
||||
umtx_shm_find_reg(const struct umtx_key *key)
|
||||
/*
|
||||
* Calls umtx_shm_find_reg_unlocked() under the 'umtx_shm_lock'.
|
||||
*/
|
||||
static int
|
||||
umtx_shm_find_reg(const struct umtx_key *key, struct umtx_shm_reg **const oreg)
|
||||
{
|
||||
struct umtx_shm_reg *reg;
|
||||
int error;
|
||||
|
||||
mtx_lock(&umtx_shm_lock);
|
||||
reg = umtx_shm_find_reg_locked(key);
|
||||
error = umtx_shm_find_reg_locked(key, oreg);
|
||||
mtx_unlock(&umtx_shm_lock);
|
||||
return (reg);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4385,42 +4405,49 @@ umtx_shm_free_reg(struct umtx_shm_reg *reg)
|
||||
}
|
||||
|
||||
static bool
|
||||
umtx_shm_unref_reg_locked(struct umtx_shm_reg *reg, bool force)
|
||||
umtx_shm_unref_reg_locked(struct umtx_shm_reg *reg, bool linked_ref)
|
||||
{
|
||||
bool res;
|
||||
|
||||
mtx_assert(&umtx_shm_lock, MA_OWNED);
|
||||
KASSERT(reg->ushm_refcnt > 0, ("ushm_reg %p refcnt 0", reg));
|
||||
reg->ushm_refcnt--;
|
||||
res = reg->ushm_refcnt == 0;
|
||||
if (res || force) {
|
||||
if ((reg->ushm_flags & USHMF_REG_LINKED) != 0) {
|
||||
TAILQ_REMOVE(&umtx_shm_registry[reg->ushm_key.hash],
|
||||
reg, ushm_reg_link);
|
||||
reg->ushm_flags &= ~USHMF_REG_LINKED;
|
||||
}
|
||||
if ((reg->ushm_flags & USHMF_OBJ_LINKED) != 0) {
|
||||
LIST_REMOVE(reg, ushm_obj_link);
|
||||
reg->ushm_flags &= ~USHMF_OBJ_LINKED;
|
||||
}
|
||||
KASSERT(reg->ushm_refcnt != 0, ("ushm_reg %p refcnt 0", reg));
|
||||
|
||||
if (linked_ref) {
|
||||
if ((reg->ushm_flags & USHMF_LINKED) == 0)
|
||||
/*
|
||||
* The reference tied to USHMF_LINKED has already been
|
||||
* released concurrently.
|
||||
*/
|
||||
return (false);
|
||||
|
||||
TAILQ_REMOVE(&umtx_shm_registry[reg->ushm_key.hash], reg,
|
||||
ushm_reg_link);
|
||||
LIST_REMOVE(reg, ushm_obj_link);
|
||||
reg->ushm_flags &= ~USHMF_LINKED;
|
||||
}
|
||||
return (res);
|
||||
|
||||
reg->ushm_refcnt--;
|
||||
return (reg->ushm_refcnt == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
umtx_shm_unref_reg(struct umtx_shm_reg *reg, bool force)
|
||||
umtx_shm_unref_reg(struct umtx_shm_reg *reg, bool linked_ref)
|
||||
{
|
||||
vm_object_t object;
|
||||
bool dofree;
|
||||
|
||||
if (force) {
|
||||
if (linked_ref) {
|
||||
/*
|
||||
* Note: This may be executed multiple times on the same
|
||||
* shared-memory VM object in presence of concurrent callers
|
||||
* because 'umtx_shm_lock' is not held all along in umtx_shm()
|
||||
* and here.
|
||||
*/
|
||||
object = reg->ushm_obj->shm_object;
|
||||
VM_OBJECT_WLOCK(object);
|
||||
vm_object_set_flag(object, OBJ_UMTXDEAD);
|
||||
VM_OBJECT_WUNLOCK(object);
|
||||
}
|
||||
mtx_lock(&umtx_shm_lock);
|
||||
dofree = umtx_shm_unref_reg_locked(reg, force);
|
||||
dofree = umtx_shm_unref_reg_locked(reg, linked_ref);
|
||||
mtx_unlock(&umtx_shm_lock);
|
||||
if (dofree)
|
||||
umtx_shm_free_reg(reg);
|
||||
@@ -4464,16 +4491,22 @@ umtx_shm_create_reg(struct thread *td, const struct umtx_key *key,
|
||||
struct ucred *cred;
|
||||
int error;
|
||||
|
||||
reg = umtx_shm_find_reg(key);
|
||||
if (reg != NULL) {
|
||||
*res = reg;
|
||||
return (0);
|
||||
error = umtx_shm_find_reg(key, res);
|
||||
if (error != ESRCH) {
|
||||
/*
|
||||
* Either no error occured, and '*res' was filled, or EOVERFLOW
|
||||
* was returned, indicating a reference count limit, and we
|
||||
* won't create a duplicate registration. In both cases, we are
|
||||
* done.
|
||||
*/
|
||||
return (error);
|
||||
}
|
||||
/* No entry, we will create one. */
|
||||
|
||||
cred = td->td_ucred;
|
||||
if (!chgumtxcnt(cred->cr_ruidinfo, 1, lim_cur(td, RLIMIT_UMTXP)))
|
||||
return (ENOMEM);
|
||||
reg = uma_zalloc(umtx_shm_reg_zone, M_WAITOK | M_ZERO);
|
||||
reg->ushm_refcnt = 1;
|
||||
bcopy(key, ®->ushm_key, sizeof(*key));
|
||||
reg->ushm_obj = shm_alloc(td->td_ucred, O_RDWR, false);
|
||||
reg->ushm_cred = crhold(cred);
|
||||
@@ -4483,18 +4516,32 @@ umtx_shm_create_reg(struct thread *td, const struct umtx_key *key,
|
||||
return (error);
|
||||
}
|
||||
mtx_lock(&umtx_shm_lock);
|
||||
reg1 = umtx_shm_find_reg_locked(key);
|
||||
if (reg1 != NULL) {
|
||||
/* Re-lookup as 'umtx_shm_lock' has been temporarily released. */
|
||||
error = umtx_shm_find_reg_locked(key, ®1);
|
||||
switch (error) {
|
||||
case 0:
|
||||
mtx_unlock(&umtx_shm_lock);
|
||||
umtx_shm_free_reg(reg);
|
||||
*res = reg1;
|
||||
return (0);
|
||||
case ESRCH:
|
||||
break;
|
||||
default:
|
||||
mtx_unlock(&umtx_shm_lock);
|
||||
umtx_shm_free_reg(reg);
|
||||
return (error);
|
||||
}
|
||||
reg->ushm_refcnt++;
|
||||
TAILQ_INSERT_TAIL(&umtx_shm_registry[key->hash], reg, ushm_reg_link);
|
||||
LIST_INSERT_HEAD(USHM_OBJ_UMTX(key->info.shared.object), reg,
|
||||
ushm_obj_link);
|
||||
reg->ushm_flags = USHMF_REG_LINKED | USHMF_OBJ_LINKED;
|
||||
reg->ushm_flags = USHMF_LINKED;
|
||||
/*
|
||||
* This is one reference for the registry and the list of shared
|
||||
* mutexes referenced by the VM object containing the lock pointer, and
|
||||
* another for the caller, which it will free after use. So, one of
|
||||
* these is tied to the presence of USHMF_LINKED.
|
||||
*/
|
||||
reg->ushm_refcnt = 2;
|
||||
mtx_unlock(&umtx_shm_lock);
|
||||
*res = reg;
|
||||
return (0);
|
||||
@@ -4553,13 +4600,9 @@ umtx_shm(struct thread *td, void *addr, u_int flags)
|
||||
if (error != 0)
|
||||
return (error);
|
||||
KASSERT(key.shared == 1, ("non-shared key"));
|
||||
if ((flags & UMTX_SHM_CREAT) != 0) {
|
||||
error = umtx_shm_create_reg(td, &key, ®);
|
||||
} else {
|
||||
reg = umtx_shm_find_reg(&key);
|
||||
if (reg == NULL)
|
||||
error = ESRCH;
|
||||
}
|
||||
error = (flags & UMTX_SHM_CREAT) != 0 ?
|
||||
umtx_shm_create_reg(td, &key, ®) :
|
||||
umtx_shm_find_reg(&key, ®);
|
||||
umtx_key_release(&key);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
+3
-1
@@ -901,8 +901,10 @@ pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio)
|
||||
|
||||
uio->uio_iov->iov_len -= size;
|
||||
uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + size;
|
||||
if (uio->uio_iov->iov_len == 0)
|
||||
if (uio->uio_iov->iov_len == 0) {
|
||||
uio->uio_iov++;
|
||||
uio->uio_iovcnt--;
|
||||
}
|
||||
uio->uio_resid -= size;
|
||||
uio->uio_offset += size;
|
||||
return (0);
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type)
|
||||
error = copyin(user_acl, &old, sizeof(old));
|
||||
if (error != 0)
|
||||
break;
|
||||
acl_copy_oldacl_into_acl(&old, kernel_acl);
|
||||
error = acl_copy_oldacl_into_acl(&old, kernel_acl);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
+3
-3
@@ -330,8 +330,8 @@ struct pfi_dynaddr {
|
||||
mtx_unlock(_s->lock); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PF_STATE_LOCK(s) mtx_lock(s->lock)
|
||||
#define PF_STATE_UNLOCK(s) mtx_unlock(s->lock)
|
||||
#define PF_STATE_LOCK(s) mtx_lock((s)->lock)
|
||||
#define PF_STATE_UNLOCK(s) mtx_unlock((s)->lock)
|
||||
#endif
|
||||
|
||||
#ifdef INVARIANTS
|
||||
@@ -2224,7 +2224,7 @@ struct pf_krule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
|
||||
struct pf_addr *, struct pf_addr *,
|
||||
uint16_t, uint16_t, struct pf_kanchor_stackframe *);
|
||||
|
||||
struct pf_state_key *pf_state_key_setup(struct pf_pdesc *, struct pf_addr *,
|
||||
struct pf_state_key *pf_state_key_setup(struct pf_pdesc *, struct mbuf *, int, struct pf_addr *,
|
||||
struct pf_addr *, u_int16_t, u_int16_t);
|
||||
struct pf_state_key *pf_state_key_clone(struct pf_state_key *);
|
||||
|
||||
|
||||
+17
-18
@@ -746,21 +746,6 @@ sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queu
|
||||
nc->do_not_ref_stcb = control->do_not_ref_stcb;
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_reset_a_control(struct sctp_queued_to_read *control,
|
||||
struct sctp_inpcb *inp, uint32_t tsn)
|
||||
{
|
||||
control->fsn_included = tsn;
|
||||
if (control->on_read_q) {
|
||||
/*
|
||||
* We have to purge it from there, hopefully this will work
|
||||
* :-)
|
||||
*/
|
||||
TAILQ_REMOVE(&inp->read_queue, control, next);
|
||||
control->on_read_q = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc,
|
||||
@@ -1922,7 +1907,8 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
SCTP_SNPRINTF(msg, sizeof(msg), "Duplicate MID=%8.8x detected.", mid);
|
||||
goto err_out;
|
||||
} else {
|
||||
if ((tsn == control->fsn_included + 1) &&
|
||||
if ((control->first_frag_seen) &&
|
||||
(tsn == control->fsn_included + 1) &&
|
||||
(control->end_added == 0)) {
|
||||
SCTP_SNPRINTF(msg, sizeof(msg),
|
||||
"Illegal message sequence, missing end for MID: %8.8x",
|
||||
@@ -5430,12 +5416,25 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
|
||||
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
if (!TAILQ_EMPTY(&control->reasm)) {
|
||||
/* This has to be old data, unordered */
|
||||
KASSERT(!asoc->idata_supported,
|
||||
("Reassembly queue not empty for I-DATA"));
|
||||
KASSERT(!ordered,
|
||||
("Reassembly queue not empty for ordered data"));
|
||||
if (control->data) {
|
||||
sctp_m_freem(control->data);
|
||||
control->data = NULL;
|
||||
}
|
||||
sctp_reset_a_control(control, stcb->sctp_ep, cumtsn);
|
||||
control->fsn_included = 0xffffffff;
|
||||
control->first_frag_seen = 0;
|
||||
control->last_frag_seen = 0;
|
||||
if (control->on_read_q) {
|
||||
/*
|
||||
* We have to purge it from there, hopefully this
|
||||
* will work :-)
|
||||
*/
|
||||
TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
|
||||
control->on_read_q = 0;
|
||||
}
|
||||
chk = TAILQ_FIRST(&control->reasm);
|
||||
if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
|
||||
TAILQ_REMOVE(&control->reasm, chk, sctp_next);
|
||||
|
||||
@@ -1448,6 +1448,7 @@ tcp_init(void)
|
||||
tcp_fastopen_init();
|
||||
|
||||
V_tcp_msl = TCPTV_MSL;
|
||||
arc4rand(&V_ts_offset_secret, sizeof(V_ts_offset_secret), 0);
|
||||
|
||||
/* Skip initialization of globals for non-default instances. */
|
||||
if (!IS_DEFAULT_VNET(curvnet))
|
||||
@@ -1481,7 +1482,6 @@ tcp_init(void)
|
||||
/* Initialize the TCP logging data. */
|
||||
tcp_log_init();
|
||||
#endif
|
||||
arc4rand(&V_ts_offset_secret, sizeof(V_ts_offset_secret), 0);
|
||||
|
||||
if (tcp_soreceive_stream) {
|
||||
#ifdef INET
|
||||
|
||||
+3
-3
@@ -1595,8 +1595,7 @@ check_release_defrouter(const struct rib_cmd_info *rc, void *_cbdata)
|
||||
struct nhop_object *nh;
|
||||
|
||||
nh = rc->rc_nh_old;
|
||||
|
||||
if ((nh != NULL) && (nh->nh_flags & NHF_DEFAULT)) {
|
||||
if (rc->rc_cmd == RTM_DELETE && (nh->nh_flags & NHF_DEFAULT) != 0) {
|
||||
dr = defrouter_lookup(&nh->gw6_sa.sin6_addr, nh->nh_ifp);
|
||||
if (dr != NULL) {
|
||||
dr->installed = 0;
|
||||
@@ -1608,9 +1607,10 @@ check_release_defrouter(const struct rib_cmd_info *rc, void *_cbdata)
|
||||
void
|
||||
nd6_subscription_cb(struct rib_head *rnh, struct rib_cmd_info *rc, void *arg)
|
||||
{
|
||||
|
||||
#ifdef ROUTE_MPATH
|
||||
rib_decompose_notification(rc, check_release_defrouter, NULL);
|
||||
if (rc->rc_cmd == RTM_DELETE && !NH_IS_NHGRP(rc->rc_nh_old))
|
||||
check_release_defrouter(rc, NULL);
|
||||
#else
|
||||
check_release_defrouter(rc, NULL);
|
||||
#endif
|
||||
|
||||
+124
-63
@@ -311,6 +311,9 @@ static int pf_test_fragment(struct pf_krule **, int,
|
||||
struct pfi_kkif *, struct mbuf *, void *,
|
||||
struct pf_pdesc *, struct pf_krule **,
|
||||
struct pf_kruleset **);
|
||||
static int pf_state_key_addr_setup(struct pf_pdesc *, struct mbuf *,
|
||||
int, struct pf_state_key_cmp *, int, struct pf_addr *,
|
||||
int, struct pf_addr *, int);
|
||||
static int pf_tcp_track_full(struct pf_kstate **,
|
||||
struct pfi_kkif *, struct mbuf *, int,
|
||||
struct pf_pdesc *, u_short *, int *);
|
||||
@@ -324,8 +327,8 @@ static int pf_test_state_udp(struct pf_kstate **, int,
|
||||
void *, struct pf_pdesc *);
|
||||
int pf_icmp_state_lookup(struct pf_state_key_cmp *,
|
||||
struct pf_pdesc *, struct pf_kstate **, struct mbuf *,
|
||||
int, struct pfi_kkif *, u_int16_t, u_int16_t,
|
||||
int, int *, int);
|
||||
int, int, struct pfi_kkif *, u_int16_t, u_int16_t,
|
||||
int, int *, int, int);
|
||||
static int pf_test_state_icmp(struct pf_kstate **, int,
|
||||
struct pfi_kkif *, struct mbuf *, int,
|
||||
void *, struct pf_pdesc *, u_short *);
|
||||
@@ -379,7 +382,7 @@ extern int pf_end_threads;
|
||||
extern struct proc *pf_purge_proc;
|
||||
|
||||
VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]);
|
||||
enum { PF_ICMP_MULTI_NONE, PF_ICMP_MULTI_SOLICITED, PF_ICMP_MULTI_LINK };
|
||||
enum { PF_ICMP_MULTI_NONE, PF_ICMP_MULTI_LINK };
|
||||
|
||||
#define PACKET_UNDO_NAT(_m, _pd, _off, _s, _dir) \
|
||||
do { \
|
||||
@@ -1423,9 +1426,66 @@ pf_state_key_ctor(void *mem, int size, void *arg, int flags)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
pf_state_key_addr_setup(struct pf_pdesc *pd, struct mbuf *m, int off,
|
||||
struct pf_state_key_cmp *key, int sidx, struct pf_addr *saddr,
|
||||
int didx, struct pf_addr *daddr, int multi)
|
||||
{
|
||||
#ifdef INET6
|
||||
struct nd_neighbor_solicit nd;
|
||||
struct pf_addr *target;
|
||||
u_short action, reason;
|
||||
|
||||
if (pd->af == AF_INET || pd->proto != IPPROTO_ICMPV6)
|
||||
goto copy;
|
||||
|
||||
switch (pd->hdr.icmp6.icmp6_type) {
|
||||
case ND_NEIGHBOR_SOLICIT:
|
||||
if (multi)
|
||||
return (-1);
|
||||
if (!pf_pull_hdr(m, off, &nd, sizeof(nd), &action, &reason, pd->af))
|
||||
return (-1);
|
||||
target = (struct pf_addr *)&nd.nd_ns_target;
|
||||
daddr = target;
|
||||
break;
|
||||
case ND_NEIGHBOR_ADVERT:
|
||||
if (multi)
|
||||
return (-1);
|
||||
if (!pf_pull_hdr(m, off, &nd, sizeof(nd), &action, &reason, pd->af))
|
||||
return (-1);
|
||||
target = (struct pf_addr *)&nd.nd_ns_target;
|
||||
saddr = target;
|
||||
if (IN6_IS_ADDR_MULTICAST(&pd->dst->v6)) {
|
||||
key->addr[didx].addr32[0] = 0;
|
||||
key->addr[didx].addr32[1] = 0;
|
||||
key->addr[didx].addr32[2] = 0;
|
||||
key->addr[didx].addr32[3] = 0;
|
||||
daddr = NULL; /* overwritten */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (multi == PF_ICMP_MULTI_LINK) {
|
||||
key->addr[sidx].addr32[0] = IPV6_ADDR_INT32_MLL;
|
||||
key->addr[sidx].addr32[1] = 0;
|
||||
key->addr[sidx].addr32[2] = 0;
|
||||
key->addr[sidx].addr32[3] = IPV6_ADDR_INT32_ONE;
|
||||
saddr = NULL; /* overwritten */
|
||||
}
|
||||
}
|
||||
copy:
|
||||
#endif
|
||||
if (saddr)
|
||||
PF_ACPY(&key->addr[sidx], saddr, pd->af);
|
||||
if (daddr)
|
||||
PF_ACPY(&key->addr[didx], daddr, pd->af);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct pf_state_key *
|
||||
pf_state_key_setup(struct pf_pdesc *pd, struct pf_addr *saddr,
|
||||
struct pf_addr *daddr, u_int16_t sport, u_int16_t dport)
|
||||
pf_state_key_setup(struct pf_pdesc *pd, struct mbuf *m, int off,
|
||||
struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t sport,
|
||||
u_int16_t dport)
|
||||
{
|
||||
struct pf_state_key *sk;
|
||||
|
||||
@@ -1433,8 +1493,12 @@ pf_state_key_setup(struct pf_pdesc *pd, struct pf_addr *saddr,
|
||||
if (sk == NULL)
|
||||
return (NULL);
|
||||
|
||||
PF_ACPY(&sk->addr[pd->sidx], saddr, pd->af);
|
||||
PF_ACPY(&sk->addr[pd->didx], daddr, pd->af);
|
||||
if (pf_state_key_addr_setup(pd, m, off, (struct pf_state_key_cmp *)sk,
|
||||
pd->sidx, pd->src, pd->didx, pd->dst, 0)) {
|
||||
uma_zfree(V_pf_state_key_z, sk);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
sk->port[pd->sidx] = sport;
|
||||
sk->port[pd->didx] = dport;
|
||||
sk->proto = pd->proto;
|
||||
@@ -4589,7 +4653,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
|
||||
if (nr == NULL) {
|
||||
KASSERT((sk == NULL && nk == NULL), ("%s: nr %p sk %p, nk %p",
|
||||
__func__, nr, sk, nk));
|
||||
sk = pf_state_key_setup(pd, pd->src, pd->dst, sport, dport);
|
||||
sk = pf_state_key_setup(pd, m, off, pd->src, pd->dst, sport, dport);
|
||||
if (sk == NULL)
|
||||
goto csfailed;
|
||||
nk = sk;
|
||||
@@ -6004,8 +6068,9 @@ pf_multihome_scan_asconf(struct mbuf *m, int start, int len,
|
||||
|
||||
int
|
||||
pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd,
|
||||
struct pf_kstate **state, struct mbuf *m, int direction, struct pfi_kkif *kif,
|
||||
u_int16_t icmpid, u_int16_t type, int icmp_dir, int *iidx, int multi)
|
||||
struct pf_kstate **state, struct mbuf *m, int off, int direction,
|
||||
struct pfi_kkif *kif, u_int16_t icmpid, u_int16_t type, int icmp_dir,
|
||||
int *iidx, int multi, int inner)
|
||||
{
|
||||
key->af = pd->af;
|
||||
key->proto = pd->proto;
|
||||
@@ -6018,31 +6083,19 @@ pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd,
|
||||
key->port[pd->sidx] = type;
|
||||
key->port[pd->didx] = icmpid;
|
||||
}
|
||||
if (pd->af == AF_INET6 && multi != PF_ICMP_MULTI_NONE) {
|
||||
switch (multi) {
|
||||
case PF_ICMP_MULTI_SOLICITED:
|
||||
key->addr[pd->sidx].addr32[0] = IPV6_ADDR_INT32_MLL;
|
||||
key->addr[pd->sidx].addr32[1] = 0;
|
||||
key->addr[pd->sidx].addr32[2] = IPV6_ADDR_INT32_ONE;
|
||||
key->addr[pd->sidx].addr32[3] = pd->src->addr32[3];
|
||||
key->addr[pd->sidx].addr8[12] = 0xff;
|
||||
break;
|
||||
case PF_ICMP_MULTI_LINK:
|
||||
key->addr[pd->sidx].addr32[0] = IPV6_ADDR_INT32_MLL;
|
||||
key->addr[pd->sidx].addr32[1] = 0;
|
||||
key->addr[pd->sidx].addr32[2] = 0;
|
||||
key->addr[pd->sidx].addr32[3] = IPV6_ADDR_INT32_ONE;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
PF_ACPY(&key->addr[pd->sidx], pd->src, key->af);
|
||||
PF_ACPY(&key->addr[pd->didx], pd->dst, key->af);
|
||||
if (pf_state_key_addr_setup(pd, m, off, key, pd->sidx, pd->src,
|
||||
pd->didx, pd->dst, multi))
|
||||
return (PF_DROP);
|
||||
|
||||
STATE_LOOKUP(kif, key, direction, *state, pd);
|
||||
|
||||
if ((*state)->state_flags & PFSTATE_SLOPPY)
|
||||
return (-1);
|
||||
|
||||
/* Is this ICMP message flowing in right direction? */
|
||||
if ((*state)->rule.ptr->type &&
|
||||
(((*state)->direction == direction) ?
|
||||
(((!inner && (*state)->direction == direction) ||
|
||||
(inner && (*state)->direction != direction)) ?
|
||||
PF_IN : PF_OUT) != icmp_dir) {
|
||||
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
||||
printf("pf: icmp type %d in wrong direction (%d): ",
|
||||
@@ -6050,6 +6103,8 @@ pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd,
|
||||
pf_print_state(*state);
|
||||
printf("\n");
|
||||
}
|
||||
PF_STATE_UNLOCK(*state);
|
||||
*state = NULL;
|
||||
return (PF_DROP);
|
||||
}
|
||||
return (-1);
|
||||
@@ -6098,19 +6153,20 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
* ICMP query/reply message not related to a TCP/UDP packet.
|
||||
* Search for an ICMP state.
|
||||
*/
|
||||
ret = pf_icmp_state_lookup(&key, pd, state, m, pd->dir,
|
||||
ret = pf_icmp_state_lookup(&key, pd, state, m, off, pd->dir,
|
||||
kif, virtual_id, virtual_type, icmp_dir, &iidx,
|
||||
PF_ICMP_MULTI_NONE);
|
||||
PF_ICMP_MULTI_NONE, 0);
|
||||
if (ret >= 0) {
|
||||
MPASS(*state == NULL);
|
||||
if (ret == PF_DROP && pd->af == AF_INET6 &&
|
||||
icmp_dir == PF_OUT) {
|
||||
if (*state != NULL)
|
||||
PF_STATE_UNLOCK((*state));
|
||||
ret = pf_icmp_state_lookup(&key, pd, state, m,
|
||||
ret = pf_icmp_state_lookup(&key, pd, state, m, off,
|
||||
pd->dir, kif, virtual_id, virtual_type,
|
||||
icmp_dir, &iidx, multi);
|
||||
if (ret >= 0)
|
||||
icmp_dir, &iidx, multi, 0);
|
||||
if (ret >= 0) {
|
||||
MPASS(*state == NULL);
|
||||
return (ret);
|
||||
}
|
||||
} else
|
||||
return (ret);
|
||||
}
|
||||
@@ -6192,6 +6248,7 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
int off2 = 0;
|
||||
|
||||
pd2.af = pd->af;
|
||||
pd2.dir = pd->dir;
|
||||
/* Payload packet is from the opposite direction. */
|
||||
pd2.sidx = (direction == PF_IN) ? 1 : 0;
|
||||
pd2.didx = (direction == PF_IN) ? 0 : 1;
|
||||
@@ -6499,9 +6556,9 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
}
|
||||
#ifdef INET
|
||||
case IPPROTO_ICMP: {
|
||||
struct icmp iih;
|
||||
struct icmp *iih = &pd2.hdr.icmp;
|
||||
|
||||
if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
|
||||
if (!pf_pull_hdr(m, off2, iih, ICMP_MINLEN,
|
||||
NULL, reason, pd2.af)) {
|
||||
DPFPRINTF(PF_DEBUG_MISC,
|
||||
("pf: ICMP error message too short i"
|
||||
@@ -6509,15 +6566,17 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
return (PF_DROP);
|
||||
}
|
||||
|
||||
icmpid = iih.icmp_id;
|
||||
pf_icmp_mapping(&pd2, iih.icmp_type,
|
||||
icmpid = iih->icmp_id;
|
||||
pf_icmp_mapping(&pd2, iih->icmp_type,
|
||||
&icmp_dir, &multi, &virtual_id, &virtual_type);
|
||||
|
||||
ret = pf_icmp_state_lookup(&key, &pd2, state, m,
|
||||
pd->dir, kif, virtual_id, virtual_type,
|
||||
icmp_dir, &iidx, PF_ICMP_MULTI_NONE);
|
||||
if (ret >= 0)
|
||||
ret = pf_icmp_state_lookup(&key, &pd2, state, m, off,
|
||||
pd2.dir, kif, virtual_id, virtual_type,
|
||||
icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1);
|
||||
if (ret >= 0) {
|
||||
MPASS(*state == NULL);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* translate source/destination address, if necessary */
|
||||
if ((*state)->key[PF_SK_WIRE] !=
|
||||
@@ -6528,10 +6587,10 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
if (PF_ANEQ(pd2.src,
|
||||
&nk->addr[pd2.sidx], pd2.af) ||
|
||||
(virtual_type == htons(ICMP_ECHO) &&
|
||||
nk->port[iidx] != iih.icmp_id))
|
||||
nk->port[iidx] != iih->icmp_id))
|
||||
pf_change_icmp(pd2.src,
|
||||
(virtual_type == htons(ICMP_ECHO)) ?
|
||||
&iih.icmp_id : NULL,
|
||||
&iih->icmp_id : NULL,
|
||||
daddr, &nk->addr[pd2.sidx],
|
||||
(virtual_type == htons(ICMP_ECHO)) ?
|
||||
nk->port[iidx] : 0, NULL,
|
||||
@@ -6547,7 +6606,7 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
|
||||
m_copyback(m, off, ICMP_MINLEN, (caddr_t)&pd->hdr.icmp);
|
||||
m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2);
|
||||
m_copyback(m, off2, ICMP_MINLEN, (caddr_t)&iih);
|
||||
m_copyback(m, off2, ICMP_MINLEN, (caddr_t)iih);
|
||||
}
|
||||
return (PF_PASS);
|
||||
break;
|
||||
@@ -6555,9 +6614,9 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case IPPROTO_ICMPV6: {
|
||||
struct icmp6_hdr iih;
|
||||
struct icmp6_hdr *iih = &pd2.hdr.icmp6;
|
||||
|
||||
if (!pf_pull_hdr(m, off2, &iih,
|
||||
if (!pf_pull_hdr(m, off2, iih,
|
||||
sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
|
||||
DPFPRINTF(PF_DEBUG_MISC,
|
||||
("pf: ICMP error message too short "
|
||||
@@ -6565,22 +6624,24 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
return (PF_DROP);
|
||||
}
|
||||
|
||||
pf_icmp_mapping(&pd2, iih.icmp6_type,
|
||||
pf_icmp_mapping(&pd2, iih->icmp6_type,
|
||||
&icmp_dir, &multi, &virtual_id, &virtual_type);
|
||||
ret = pf_icmp_state_lookup(&key, &pd2, state, m,
|
||||
|
||||
ret = pf_icmp_state_lookup(&key, &pd2, state, m, off,
|
||||
pd->dir, kif, virtual_id, virtual_type,
|
||||
icmp_dir, &iidx, PF_ICMP_MULTI_NONE);
|
||||
icmp_dir, &iidx, PF_ICMP_MULTI_NONE, 1);
|
||||
if (ret >= 0) {
|
||||
if (ret == PF_DROP && pd->af == AF_INET6 &&
|
||||
MPASS(*state == NULL);
|
||||
if (ret == PF_DROP && pd2.af == AF_INET6 &&
|
||||
icmp_dir == PF_OUT) {
|
||||
if (*state != NULL)
|
||||
PF_STATE_UNLOCK((*state));
|
||||
ret = pf_icmp_state_lookup(&key, pd,
|
||||
state, m, pd->dir, kif,
|
||||
ret = pf_icmp_state_lookup(&key, &pd2,
|
||||
state, m, off, pd->dir, kif,
|
||||
virtual_id, virtual_type,
|
||||
icmp_dir, &iidx, multi);
|
||||
if (ret >= 0)
|
||||
icmp_dir, &iidx, multi, 1);
|
||||
if (ret >= 0) {
|
||||
MPASS(*state == NULL);
|
||||
return (ret);
|
||||
}
|
||||
} else
|
||||
return (ret);
|
||||
}
|
||||
@@ -6594,10 +6655,10 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
if (PF_ANEQ(pd2.src,
|
||||
&nk->addr[pd2.sidx], pd2.af) ||
|
||||
((virtual_type == htons(ICMP6_ECHO_REQUEST)) &&
|
||||
nk->port[pd2.sidx] != iih.icmp6_id))
|
||||
nk->port[pd2.sidx] != iih->icmp6_id))
|
||||
pf_change_icmp(pd2.src,
|
||||
(virtual_type == htons(ICMP6_ECHO_REQUEST))
|
||||
? &iih.icmp6_id : NULL,
|
||||
? &iih->icmp6_id : NULL,
|
||||
daddr, &nk->addr[pd2.sidx],
|
||||
(virtual_type == htons(ICMP6_ECHO_REQUEST))
|
||||
? nk->port[iidx] : 0, NULL,
|
||||
@@ -6615,7 +6676,7 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif
|
||||
(caddr_t)&pd->hdr.icmp6);
|
||||
m_copyback(m, ipoff2, sizeof(h2_6), (caddr_t)&h2_6);
|
||||
m_copyback(m, off2, sizeof(struct icmp6_hdr),
|
||||
(caddr_t)&iih);
|
||||
(caddr_t)iih);
|
||||
}
|
||||
return (PF_PASS);
|
||||
break;
|
||||
|
||||
@@ -606,7 +606,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
*skp = pf_state_key_setup(pd, saddr, daddr, sport, dport);
|
||||
*skp = pf_state_key_setup(pd, m, off, saddr, daddr, sport, dport);
|
||||
if (*skp == NULL)
|
||||
return (NULL);
|
||||
*nkp = pf_state_key_clone(*skp);
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1303503 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1304000 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
||||
@@ -71,7 +71,74 @@ cve_2019_5598_cleanup()
|
||||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "ttl_exceeded" "cleanup"
|
||||
ttl_exceeded_head()
|
||||
{
|
||||
atf_set descr 'Test that we correctly translate TTL exceeded back'
|
||||
atf_set require.user root
|
||||
}
|
||||
|
||||
ttl_exceeded_body()
|
||||
{
|
||||
pft_init
|
||||
|
||||
epair_srv=$(vnet_mkepair)
|
||||
epair_int=$(vnet_mkepair)
|
||||
epair_cl=$(vnet_mkepair)
|
||||
|
||||
vnet_mkjail srv ${epair_srv}a
|
||||
jexec srv ifconfig ${epair_srv}a 192.0.2.1/24 up
|
||||
jexec srv route add default 192.0.2.2
|
||||
|
||||
vnet_mkjail int ${epair_srv}b ${epair_int}a
|
||||
jexec int sysctl net.inet.ip.forwarding=1
|
||||
jexec int ifconfig ${epair_srv}b 192.0.2.2/24 up
|
||||
jexec int ifconfig ${epair_int}a 203.0.113.2/24 up
|
||||
|
||||
vnet_mkjail nat ${epair_int}b ${epair_cl}b
|
||||
jexec nat ifconfig ${epair_int}b 203.0.113.1/24 up
|
||||
jexec nat ifconfig ${epair_cl}b 198.51.100.2/24 up
|
||||
jexec nat sysctl net.inet.ip.forwarding=1
|
||||
jexec nat route add default 203.0.113.2
|
||||
|
||||
vnet_mkjail cl ${epair_cl}a
|
||||
jexec cl ifconfig ${epair_cl}a 198.51.100.1/24 up
|
||||
jexec cl route add default 198.51.100.2
|
||||
|
||||
jexec nat pfctl -e
|
||||
pft_set_rules nat \
|
||||
"nat on ${epair_int}b from 198.51.100.0/24 -> (${epair_int}b)" \
|
||||
"block" \
|
||||
"pass inet proto udp" \
|
||||
"pass inet proto icmp icmp-type { echoreq }"
|
||||
|
||||
# Sanity checks
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 198.51.100.2
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 203.0.113.1
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 203.0.113.2
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 192.0.2.1
|
||||
|
||||
echo "UDP"
|
||||
atf_check -s exit:0 -e ignore -o match:".*203.0.113.2.*" \
|
||||
jexec cl traceroute 192.0.2.1
|
||||
jexec nat pfctl -Fs
|
||||
|
||||
echo "ICMP"
|
||||
atf_check -s exit:0 -e ignore -o match:".*203.0.113.2.*" \
|
||||
jexec cl traceroute -I 192.0.2.1
|
||||
}
|
||||
|
||||
ttl_exceeded_cleanup()
|
||||
{
|
||||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case "cve_2019_5598"
|
||||
atf_add_test_case "ttl_exceeded"
|
||||
}
|
||||
@@ -83,7 +83,74 @@ zero_id_cleanup()
|
||||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "ttl_exceeded" "cleanup"
|
||||
ttl_exceeded_head()
|
||||
{
|
||||
atf_set descr 'Test that we correctly translate TTL exceeded back'
|
||||
atf_set require.user root
|
||||
}
|
||||
|
||||
ttl_exceeded_body()
|
||||
{
|
||||
pft_init
|
||||
|
||||
epair_srv=$(vnet_mkepair)
|
||||
epair_int=$(vnet_mkepair)
|
||||
epair_cl=$(vnet_mkepair)
|
||||
|
||||
vnet_mkjail srv ${epair_srv}a
|
||||
jexec srv ifconfig ${epair_srv}a inet6 2001:db8:1::1/64 no_dad up
|
||||
jexec srv route add -6 default 2001:db8:1::2
|
||||
|
||||
vnet_mkjail int ${epair_srv}b ${epair_int}a
|
||||
jexec int sysctl net.inet6.ip6.forwarding=1
|
||||
jexec int ifconfig ${epair_srv}b inet6 2001:db8:1::2/64 no_dad up
|
||||
jexec int ifconfig ${epair_int}a inet6 2001:db8:2::2/64 no_dad up
|
||||
|
||||
vnet_mkjail nat ${epair_int}b ${epair_cl}b
|
||||
jexec nat ifconfig ${epair_int}b inet6 2001:db8:2::1 no_dad up
|
||||
jexec nat ifconfig ${epair_cl}b inet6 2001:db8:3::2/64 no_dad up
|
||||
jexec nat sysctl net.inet6.ip6.forwarding=1
|
||||
jexec nat route add -6 default 2001:db8:2::2
|
||||
|
||||
vnet_mkjail cl ${epair_cl}a
|
||||
jexec cl ifconfig ${epair_cl}a inet6 2001:db8:3::1/64 no_dad up
|
||||
jexec cl route add -6 default 2001:db8:3::2
|
||||
|
||||
jexec nat pfctl -e
|
||||
pft_set_rules nat \
|
||||
"nat on ${epair_int}b from 2001:db8:3::/64 -> (${epair_int}b:0)" \
|
||||
"block" \
|
||||
"pass inet6 proto udp" \
|
||||
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv, echoreq }"
|
||||
|
||||
# Sanity checks
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 2001:db8:3::2
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 2001:db8:2::1
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 2001:db8:2::2
|
||||
atf_check -s exit:0 -o ignore \
|
||||
jexec cl ping -c 1 2001:db8:1::1
|
||||
|
||||
echo "UDP"
|
||||
atf_check -s exit:0 -e ignore -o match:".*2001:db8:2::2.*" \
|
||||
jexec cl traceroute6 2001:db8:1::1
|
||||
jexec nat pfctl -Fs
|
||||
|
||||
echo "ICMP"
|
||||
atf_check -s exit:0 -e ignore -o match:".*2001:db8:2::2.*" \
|
||||
jexec cl traceroute6 -I 2001:db8:1::1
|
||||
}
|
||||
|
||||
ttl_exceeded_cleanup()
|
||||
{
|
||||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case "zero_id"
|
||||
atf_add_test_case "ttl_exceeded"
|
||||
}
|
||||
@@ -224,7 +224,7 @@ main(int argc, char *argv[])
|
||||
|
||||
lc = login_getpwclass(pw);
|
||||
if (setusercontext(lc, pw, pw->pw_uid,
|
||||
LOGIN_SETALL) != 0)
|
||||
LOGIN_SETALL & ~LOGIN_SETLOGIN) != 0)
|
||||
errx(1, "setusercontext");
|
||||
setenv("HOME", pw->pw_dir, 1);
|
||||
cal();
|
||||
|
||||
@@ -382,7 +382,8 @@ follow(file_info_t *files, enum STYLE style, off_t off)
|
||||
sb2.st_dev != file->st.st_dev ||
|
||||
sb2.st_nlink == 0) {
|
||||
show(file);
|
||||
fclose(file->fp);
|
||||
if (file->fp != NULL)
|
||||
fclose(file->fp);
|
||||
file->fp = ftmp;
|
||||
memcpy(&file->st, &sb2,
|
||||
sizeof(struct stat));
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd April 12, 2007
|
||||
.Dd August 18, 2024
|
||||
.Dt ADDUSER.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -171,8 +171,12 @@ The default information to be held in the GECOS field of
|
||||
.It Va uidstart
|
||||
The default user ID setting.
|
||||
This must be a number above 1000 and fewer than 65534.
|
||||
.It Va Zflag
|
||||
Do not attempt to create ZFS home dataset.
|
||||
.It Va Zcreate
|
||||
Set to
|
||||
.Dq no
|
||||
to prevent the creation of a ZFS home dataset if
|
||||
.Va homeprefix
|
||||
is a ZFS mountpoint.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
The following is an example
|
||||
|
||||
@@ -474,7 +474,7 @@ get_homeperm() {
|
||||
# so, enable ZFS home dataset creation.
|
||||
#
|
||||
get_zfs_home() {
|
||||
local _prefix=
|
||||
local _prefix= _tmp=
|
||||
|
||||
# check if zfs kernel module is loaded before attempting to run zfs to
|
||||
# prevent loading the kernel module on systems that don't use ZFS
|
||||
@@ -487,6 +487,13 @@ get_zfs_home() {
|
||||
Zcreate="no"
|
||||
return
|
||||
fi
|
||||
# Make sure that _prefix is not a subdirectory within a dataset. If it
|
||||
# is, the containing dataset will be the same for it and its parent.
|
||||
_tmp=$(${ZFSCMD} list -Ho name "$(dirname "${homeprefix}")" 2>/dev/null)
|
||||
if [ "${_tmp}" = "${_prefix}" ]; then
|
||||
Zcreate="no"
|
||||
return
|
||||
fi
|
||||
zhome="${_prefix}/${username}"
|
||||
}
|
||||
|
||||
|
||||
@@ -659,7 +659,7 @@ pci_xhci_init_ep(struct pci_xhci_dev_emu *dev, int epid)
|
||||
devep = &dev->eps[epid];
|
||||
pstreams = XHCI_EPCTX_0_MAXP_STREAMS_GET(ep_ctx->dwEpCtx0);
|
||||
if (pstreams > 0) {
|
||||
DPRINTF(("init_ep %d with pstreams %d", epid, pstreams));
|
||||
DPRINTF(("init_ep %d with pstreams %u", epid, pstreams));
|
||||
assert(devep->ep_sctx_trbs == NULL);
|
||||
|
||||
devep->ep_sctx = XHCI_GADDR(dev->xsc, ep_ctx->qwEpCtx2 &
|
||||
@@ -1201,7 +1201,7 @@ pci_xhci_find_stream(struct pci_xhci_softc *sc, struct xhci_endp_ctx *ep,
|
||||
}
|
||||
|
||||
/* only support primary stream */
|
||||
if (streamid > devep->ep_MaxPStreams)
|
||||
if (streamid >= devep->ep_MaxPStreams)
|
||||
return (XHCI_TRB_ERROR_STREAM_TYPE);
|
||||
|
||||
sctx = (struct xhci_stream_ctx *)XHCI_GADDR(sc, ep->qwEpCtx2 & ~0xFUL) +
|
||||
|
||||
+5
-1
@@ -741,6 +741,9 @@ Secondly, it will only remove files and directories that are actually owned by
|
||||
the user, or symbolic links owned by anyone under the user's home directory.
|
||||
Finally, after deleting all contents owned by the user only empty directories
|
||||
will be removed.
|
||||
If the home directory is a ZFS dataset and has been emptied,
|
||||
the dataset will be destroyed.
|
||||
ZFS datasets within the home directory and snapshots are not handled.
|
||||
If any additional cleanup work is required, this is left to the administrator.
|
||||
.El
|
||||
.Pp
|
||||
@@ -1077,7 +1080,8 @@ No base home directory configured.
|
||||
.Xr passwd 5 ,
|
||||
.Xr pw.conf 5 ,
|
||||
.Xr pwd_mkdb 8 ,
|
||||
.Xr vipw 8
|
||||
.Xr vipw 8 ,
|
||||
.Xr zfs 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
||||
+10
-5
@@ -28,7 +28,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
@@ -687,6 +687,7 @@ rmat(uid_t uid)
|
||||
|
||||
while ((e = readdir(d)) != NULL) {
|
||||
struct stat st;
|
||||
pid_t pid;
|
||||
|
||||
if (strncmp(e->d_name, ".lock", 5) != 0 &&
|
||||
stat(e->d_name, &st) == 0 &&
|
||||
@@ -697,11 +698,12 @@ rmat(uid_t uid)
|
||||
e->d_name,
|
||||
NULL
|
||||
};
|
||||
if (posix_spawn(NULL, argv[0], NULL, NULL,
|
||||
if (posix_spawn(&pid, argv[0], NULL, NULL,
|
||||
(char *const *) argv, environ)) {
|
||||
warn("Failed to execute '%s %s'",
|
||||
argv[0], argv[1]);
|
||||
}
|
||||
} else
|
||||
(void) waitpid(pid, NULL, 0);
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
@@ -971,11 +973,14 @@ pw_user_del(int argc, char **argv, char *arg1)
|
||||
"-r",
|
||||
NULL
|
||||
};
|
||||
if (posix_spawnp(NULL, argv[0], NULL, NULL,
|
||||
pid_t pid;
|
||||
|
||||
if (posix_spawnp(&pid, argv[0], NULL, NULL,
|
||||
(char *const *) argv, environ)) {
|
||||
warn("Failed to execute '%s %s'",
|
||||
argv[0], argv[1]);
|
||||
}
|
||||
} else
|
||||
(void) waitpid(pid, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ void vendgrent(void);
|
||||
|
||||
void copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid,
|
||||
gid_t gid, int flags);
|
||||
void rm_r(int rootfd, char const * dir, uid_t uid);
|
||||
bool rm_r(int rootfd, char const * dir, uid_t uid);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_PWUPD_H */
|
||||
+102
-11
@@ -26,35 +26,58 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <libutil.h>
|
||||
#include <spawn.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pwupd.h"
|
||||
|
||||
void
|
||||
static bool try_dataset_remove(const char *home);
|
||||
extern char **environ;
|
||||
|
||||
/*
|
||||
* "rm -r" a directory tree. If the top-level directory cannot be removed
|
||||
* due to EBUSY, indicating that it is a ZFS dataset, and we have emptied
|
||||
* it, destroy the dataset. Return true if any files or directories
|
||||
* remain.
|
||||
*/
|
||||
bool
|
||||
rm_r(int rootfd, const char *path, uid_t uid)
|
||||
{
|
||||
int dirfd;
|
||||
DIR *d;
|
||||
struct dirent *e;
|
||||
struct stat st;
|
||||
const char *fullpath;
|
||||
bool skipped = false;
|
||||
|
||||
fullpath = path;
|
||||
if (*path == '/')
|
||||
path++;
|
||||
|
||||
dirfd = openat(rootfd, path, O_DIRECTORY);
|
||||
if (dirfd == -1) {
|
||||
return;
|
||||
return (true);
|
||||
}
|
||||
|
||||
d = fdopendir(dirfd);
|
||||
if (d == NULL) {
|
||||
(void)close(dirfd);
|
||||
return;
|
||||
return (true);
|
||||
}
|
||||
while ((e = readdir(d)) != NULL) {
|
||||
if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
|
||||
@@ -62,16 +85,84 @@ rm_r(int rootfd, const char *path, uid_t uid)
|
||||
|
||||
if (fstatat(dirfd, e->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
rm_r(dirfd, e->d_name, uid);
|
||||
else if (S_ISLNK(st.st_mode) || st.st_uid == uid)
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (rm_r(dirfd, e->d_name, uid) == true)
|
||||
skipped = true;
|
||||
} else if (S_ISLNK(st.st_mode) || st.st_uid == uid)
|
||||
unlinkat(dirfd, e->d_name, 0);
|
||||
else
|
||||
skipped = true;
|
||||
}
|
||||
closedir(d);
|
||||
if (fstatat(rootfd, path, &st, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
return;
|
||||
if (S_ISLNK(st.st_mode))
|
||||
unlinkat(rootfd, path, 0);
|
||||
else if (st.st_uid == uid)
|
||||
unlinkat(rootfd, path, AT_REMOVEDIR);
|
||||
return (skipped);
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
if (unlinkat(rootfd, path, 0) == -1)
|
||||
skipped = true;
|
||||
} else if (st.st_uid == uid) {
|
||||
if (unlinkat(rootfd, path, AT_REMOVEDIR) == -1) {
|
||||
if (errno == EBUSY && skipped == false)
|
||||
skipped = try_dataset_remove(fullpath);
|
||||
else
|
||||
skipped = true;
|
||||
}
|
||||
} else
|
||||
skipped = true;
|
||||
|
||||
return (skipped);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the home directory is a ZFS dataset, attempt to destroy it.
|
||||
* Return true if the dataset is not destroyed.
|
||||
* This would be more straightforward as a shell script.
|
||||
*/
|
||||
static bool
|
||||
try_dataset_remove(const char *path)
|
||||
{
|
||||
bool skipped = true;
|
||||
struct statfs stat;
|
||||
const char *argv[] = {
|
||||
"/sbin/zfs",
|
||||
"destroy",
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
/* see if this is an absolute path (top-level directory) */
|
||||
if (*path != '/')
|
||||
return (skipped);
|
||||
/* see if ZFS is loaded */
|
||||
if (kld_isloaded("zfs") == 0)
|
||||
return (skipped);
|
||||
/* This won't work if root dir is not / (-R option) */
|
||||
if (strcmp(conf.rootdir, "/") != 0) {
|
||||
warnx("cannot destroy home dataset when -R was used");
|
||||
return (skipped);
|
||||
}
|
||||
/* if so, find dataset name */
|
||||
if (statfs(path, &stat) != 0) {
|
||||
warn("statfs %s", path);
|
||||
return (skipped);
|
||||
}
|
||||
/*
|
||||
* Check that the path refers to the dataset itself,
|
||||
* not a subdirectory.
|
||||
*/
|
||||
if (strcmp(stat.f_mntonname, path) != 0)
|
||||
return (skipped);
|
||||
argv[2] = stat.f_mntfromname;
|
||||
if ((skipped = posix_spawn(&pid, argv[0], NULL, NULL,
|
||||
(char *const *) argv, environ)) != 0) {
|
||||
warn("Failed to execute '%s %s %s'",
|
||||
argv[0], argv[1], argv[2]);
|
||||
} else {
|
||||
if (waitpid(pid, &status, 0) != -1 && status != 0) {
|
||||
warnx("'%s %s %s' exit status %d\n",
|
||||
argv[0], argv[1], argv[2], status);
|
||||
}
|
||||
}
|
||||
return (skipped);
|
||||
}
|
||||
Reference in new issue
Block a user