#include <sys/kauth.h>
#include <sys/file_internal.h>
#include <sys/guarded.h>
+#include <sys/priv.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
struct vnode *dst_vp = NULLVP;
/* We need to grab the 2nd FD out of the argments before moving on. */
int fd2 = CAST_DOWN_EXPLICIT(int32_t, uap->arg);
-
+
+ error = priv_check_cred(kauth_cred_get(), PRIV_VFS_MOVE_DATA_EXTENTS, 0);
+ if (error)
+ goto out;
+
if (fp->f_type != DTYPE_VNODE) {
error = EBADF;
goto out;
/*
* VFS privileges
*/
-#define PRIV_VFS_OPEN_BY_ID 14000 /*Allow calling openbyid_np()*/
+#define PRIV_VFS_OPEN_BY_ID 14000 /* Allow calling openbyid_np() */
+#define PRIV_VFS_MOVE_DATA_EXTENTS 14001 /* Allow F_MOVEDATAEXTENTS fcntl */
#ifdef KERNEL
/*
-15.2.0
+15.3.0
# The first line of this file contains the master version number for the kernel.
# All other instances of the kernel version in xnu are derived from this file.
#endif
OSSet * mappings;
UInt8 sharedInstance;
- UInt8 __reservedA[3];
+ UInt8 closed;
+ UInt8 __reservedA[2];
void * __reserved[7];
public:
void IOBufferMemoryDescriptor::setLength(vm_size_t length)
{
assert(length <= _capacity);
+ if (length > _capacity) return;
_length = length;
_ranges.v64->length = length;
// Find starting address within the vector of ranges
Ranges vec = _ranges;
- UInt32 length = 0;
- UInt32 pages = 0;
- for (unsigned ind = 0; ind < count; ind++) {
+ mach_vm_size_t totalLength = 0;
+ unsigned int ind, pages = 0;
+ for (ind = 0; ind < count; ind++) {
mach_vm_address_t addr;
mach_vm_size_t len;
// addr & len are returned by this function
getAddrLenForInd(addr, len, type, vec, ind);
+ if ((addr + len + PAGE_MASK) < addr) break; /* overflow */
pages += (atop_64(addr + len + PAGE_MASK) - atop_64(addr));
- len += length;
- assert(len >= length); // Check for 32 bit wrap around
- length = len;
-
+ totalLength += len;
+ if (totalLength < len) break; /* overflow */
if ((kIOMemoryTypePhysical == type) || (kIOMemoryTypePhysical64 == type))
{
ppnum_t highPage = atop_64(addr + len - 1);
_highestPage = highPage;
}
}
- _length = length;
+ if ((ind < count)
+ || (totalLength != ((IOByteCount) totalLength))) return (false); /* overflow */
+
+ _length = totalLength;
_pages = pages;
_rangesCount = count;
_wireCount++; // Physical MDs are, by definition, wired
else { /* kIOMemoryTypeVirtual | kIOMemoryTypeVirtual64 | kIOMemoryTypeUIO */
ioGMDData *dataP;
- unsigned dataSize = computeDataSize(_pages, /* upls */ count * 2);
+ mach_vm_size_t dataSize = computeDataSize(_pages, /* upls */ count * 2);
+ if (dataSize != ((unsigned) dataSize)) return false; /* overflow */
if (!initMemoryEntries(dataSize, mapper)) return false;
dataP = getDataP(_memoryEntries);
// Assert that this entire I/O is withing the available range
assert(offset <= _length);
assert(offset + length <= _length);
- if (offset >= _length) {
+ if ((offset >= _length)
+ || ((offset + length) > _length)) {
return 0;
}
assert( !(kIOMemoryPreparedReadOnly & _flags) );
- if ( (kIOMemoryPreparedReadOnly & _flags) || offset >= _length) {
+ if ( (kIOMemoryPreparedReadOnly & _flags)
+ || (offset >= _length)
+ || ((offset + length) > _length)) {
return 0;
}
IOReturn IOUserClient::clientDied( void )
{
- return( clientClose());
+ IOReturn ret = kIOReturnNotReady;
+
+ if (sharedInstance || OSCompareAndSwap8(0, 1, &closed))
+ {
+ ret = clientClose();
+ }
+
+ return (ret);
}
IOReturn IOUserClient::clientClose( void )
if( KERN_SUCCESS == kr) {
// must return success after vm_map_copyout() succeeds
+ // and mig will copy out objects on success
+ *existing = 0;
*result = internal_io_service_get_matching_services(master_port,
(const char *) data, matchingCnt, existing);
vm_deallocate( kernel_map, data, matchingCnt );
if( KERN_SUCCESS == kr) {
// must return success after vm_map_copyout() succeeds
+ // and mig will copy out objects on success
+ *service = 0;
*result = internal_io_service_get_matching_service(master_port,
(const char *) data, matchingCnt, service );
vm_deallocate( kernel_map, data, matchingCnt );
if( KERN_SUCCESS == kr) {
// must return success after vm_map_copyout() succeeds
+ // and mig will copy out objects on success
+ *notification = 0;
*result = internal_io_service_add_notification( master_port, notification_type,
(char *) data, matchingCnt, wake_port, reference, referenceSize, client64, notification );
vm_deallocate( kernel_map, data, matchingCnt );
break;
}
client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
+ client->closed = false;
OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
if (creatorName)
{
CHECK( IOUserClient, connection, client );
IOStatisticsClientCall();
- client->clientClose();
+
+ if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed))
+ {
+ client->clientClose();
+ }
+ else
+ {
+ IOLog("ignored is_io_service_close(0x%qx,%s)\n",
+ client->getRegistryEntryID(), client->getName());
+ }
return( kIOReturnSuccess );
}
kxld_types.h \
stack_protector.h
-INSTALL_KF_MI_LCL_LIST += \
- section_keywords.h
-EXPORT_MI_LIST += \
- section_keywords.h
EXPORT_MI_GEN_LIST = version.h