1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Kernel-Mode Test Suite Io Regressions KM-Test (IoCreateFile) 5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org> 6 */ 7 8 #include <kmt_test.h> 9 10 static UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot\\"); 11 static UNICODE_STRING Regedit = RTL_CONSTANT_STRING(L"regedit.exe"); 12 static UNICODE_STRING Foobar = RTL_CONSTANT_STRING(L"foobar.exe"); 13 static UNICODE_STRING SystemRootRegedit = RTL_CONSTANT_STRING(L"\\SystemRoot\\regedit.exe"); 14 static UNICODE_STRING SystemRootFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar.exe"); 15 static UNICODE_STRING SystemRootFoobarFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar\\foobar.exe"); 16 static UNICODE_STRING FoobarFoobar = RTL_CONSTANT_STRING(L"foobar\\foobar.exe"); 17 18 static 19 VOID 20 NTAPI 21 KernelModeTest(IN PVOID Context) 22 { 23 NTSTATUS Status; 24 IO_STATUS_BLOCK IoStatusBlock; 25 OBJECT_ATTRIBUTES ObjectAttributes; 26 HANDLE ParentHandle, SystemRootHandle, TargetHandle; 27 PFILE_OBJECT ParentFileObject, TargetFileObject, SystemRootFileObject; 28 29 UNREFERENCED_PARAMETER(Context); 30 31 /* Kernelmode mandatory for IoCreateFile */ 32 ok(ExGetPreviousMode() == KernelMode, "UserMode returned!\n"); 33 34 /* First of all, open \\SystemRoot 35 * We're interested in 3 pieces of information about it: 36 * -> Its target (it's a symlink): \Windows or \ReactOS 37 * -> Its associated File Object 38 * -> Its associated FCB 39 */ 40 TargetFileObject = NULL; 41 IoStatusBlock.Status = 0xFFFFFFFF; 42 TargetHandle = INVALID_HANDLE_VALUE; 43 IoStatusBlock.Information = 0xFFFFFFFF; 44 InitializeObjectAttributes(&ObjectAttributes, 45 &SystemRoot, 46 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 47 NULL, NULL); 48 Status = ZwOpenFile(&TargetHandle, 49 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 50 &ObjectAttributes, 51 &IoStatusBlock, 52 FILE_SHARE_READ | FILE_SHARE_WRITE, 53 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 54 ok_eq_hex(Status, STATUS_SUCCESS); 55 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 56 if (Status == STATUS_SUCCESS) 57 { 58 Status = ObReferenceObjectByHandle(TargetHandle, 59 FILE_READ_DATA, 60 *IoFileObjectType, 61 KernelMode, 62 (PVOID *)&TargetFileObject, 63 NULL); 64 ok_eq_hex(Status, STATUS_SUCCESS); 65 } 66 67 ok(TargetFileObject != NULL, "Not target to continue!\n"); 68 if (TargetFileObject == NULL) 69 { 70 if (TargetHandle != INVALID_HANDLE_VALUE) 71 { 72 ObCloseHandle(TargetHandle, KernelMode); 73 } 74 return; 75 } 76 77 /* Open target directory of \SystemRoot\Regedit.exe 78 * This must lead to \SystemRoot opening 79 */ 80 IoStatusBlock.Status = 0xFFFFFFFF; 81 IoStatusBlock.Information = 0xFFFFFFFF; 82 InitializeObjectAttributes(&ObjectAttributes, 83 &SystemRootRegedit, 84 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 85 NULL, NULL); 86 Status = IoCreateFile(&ParentHandle, 87 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 88 &ObjectAttributes, 89 &IoStatusBlock, 90 NULL, 91 0, 92 FILE_SHARE_READ | FILE_SHARE_WRITE, 93 FILE_OPEN, 94 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 95 NULL, 96 0, 97 CreateFileTypeNone, 98 NULL, 99 IO_OPEN_TARGET_DIRECTORY); 100 ok_eq_hex(Status, STATUS_SUCCESS); 101 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 102 if (Status == STATUS_SUCCESS) 103 { 104 Status = ObReferenceObjectByHandle(ParentHandle, 105 FILE_READ_DATA, 106 *IoFileObjectType, 107 KernelMode, 108 (PVOID *)&ParentFileObject, 109 NULL); 110 ok_eq_hex(Status, STATUS_SUCCESS); 111 if (Status == STATUS_SUCCESS) 112 { 113 /* At that point, file object must point to \SystemRoot 114 * But must not be the same FO than target (diverted file object) 115 * This means FCB & FileName are equal 116 * But CCB & FO are different 117 * CCB must be != NULL, otherwise it means open failed 118 */ 119 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); 120 ok_eq_pointer(ParentFileObject->RelatedFileObject, NULL); 121 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); 122 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); 123 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); 124 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); 125 ObDereferenceObject(ParentFileObject); 126 } 127 /* Because target exists FSD must signal it */ 128 ok_eq_long(IoStatusBlock.Information, FILE_EXISTS); 129 ObCloseHandle(ParentHandle, KernelMode); 130 } 131 132 /* Do the same with relative open */ 133 IoStatusBlock.Status = 0xFFFFFFFF; 134 IoStatusBlock.Information = 0xFFFFFFFF; 135 InitializeObjectAttributes(&ObjectAttributes, 136 &SystemRoot, 137 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 138 NULL, NULL); 139 Status = ZwOpenFile(&SystemRootHandle, 140 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 141 &ObjectAttributes, 142 &IoStatusBlock, 143 FILE_SHARE_READ | FILE_SHARE_WRITE, 144 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 145 ok_eq_hex(Status, STATUS_SUCCESS); 146 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 147 if (Status == STATUS_SUCCESS) 148 { 149 IoStatusBlock.Status = 0xFFFFFFFF; 150 IoStatusBlock.Information = 0xFFFFFFFF; 151 InitializeObjectAttributes(&ObjectAttributes, 152 &Regedit, 153 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 154 SystemRootHandle, 155 NULL); 156 Status = IoCreateFile(&ParentHandle, 157 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 158 &ObjectAttributes, 159 &IoStatusBlock, 160 NULL, 161 0, 162 FILE_SHARE_READ | FILE_SHARE_WRITE, 163 FILE_OPEN, 164 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 165 NULL, 166 0, 167 CreateFileTypeNone, 168 NULL, 169 IO_OPEN_TARGET_DIRECTORY); 170 ok_eq_hex(Status, STATUS_SUCCESS); 171 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 172 if (Status == STATUS_SUCCESS) 173 { 174 Status = ObReferenceObjectByHandle(ParentHandle, 175 FILE_READ_DATA, 176 *IoFileObjectType, 177 KernelMode, 178 (PVOID *)&ParentFileObject, 179 NULL); 180 ok_eq_hex(Status, STATUS_SUCCESS); 181 if (Status == STATUS_SUCCESS) 182 { 183 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); 184 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); 185 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); 186 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); 187 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); 188 Status = ObReferenceObjectByHandle(SystemRootHandle, 189 FILE_READ_DATA, 190 *IoFileObjectType, 191 KernelMode, 192 (PVOID *)&SystemRootFileObject, 193 NULL); 194 ok_eq_hex(Status, STATUS_SUCCESS); 195 if (Status == STATUS_SUCCESS) 196 { 197 ok_eq_pointer(ParentFileObject->RelatedFileObject, SystemRootFileObject); 198 ok(ParentFileObject->RelatedFileObject != TargetFileObject, "File objects must be different\n"); 199 ok(SystemRootFileObject != TargetFileObject, "File objects must be different\n"); 200 ObDereferenceObject(SystemRootFileObject); 201 } 202 ObDereferenceObject(ParentFileObject); 203 } 204 ok_eq_long(IoStatusBlock.Information, FILE_EXISTS); 205 ObCloseHandle(ParentHandle, KernelMode); 206 } 207 ObCloseHandle(SystemRootHandle, KernelMode); 208 } 209 210 /* *** */ 211 212 /* Now redo the same scheme, but using a target that doesn't exist 213 * The difference will be in IoStatusBlock.Information, the FSD will 214 * inform that the target doesn't exist. 215 * Clear for rename :-) 216 */ 217 IoStatusBlock.Status = 0xFFFFFFFF; 218 IoStatusBlock.Information = 0xFFFFFFFF; 219 InitializeObjectAttributes(&ObjectAttributes, 220 &SystemRootFoobar, 221 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 222 NULL, NULL); 223 Status = IoCreateFile(&ParentHandle, 224 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 225 &ObjectAttributes, 226 &IoStatusBlock, 227 NULL, 228 0, 229 FILE_SHARE_READ | FILE_SHARE_WRITE, 230 FILE_OPEN, 231 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 232 NULL, 233 0, 234 CreateFileTypeNone, 235 NULL, 236 IO_OPEN_TARGET_DIRECTORY); 237 ok_eq_hex(Status, STATUS_SUCCESS); 238 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 239 if (Status == STATUS_SUCCESS) 240 { 241 Status = ObReferenceObjectByHandle(ParentHandle, 242 FILE_READ_DATA, 243 *IoFileObjectType, 244 KernelMode, 245 (PVOID *)&ParentFileObject, 246 NULL); 247 ok_eq_hex(Status, STATUS_SUCCESS); 248 if (Status == STATUS_SUCCESS) 249 { 250 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); 251 ok_eq_pointer(ParentFileObject->RelatedFileObject, NULL); 252 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); 253 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); 254 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); 255 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); 256 ObDereferenceObject(ParentFileObject); 257 } 258 ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST); 259 ObCloseHandle(ParentHandle, KernelMode); 260 } 261 262 IoStatusBlock.Status = 0xFFFFFFFF; 263 IoStatusBlock.Information = 0xFFFFFFFF; 264 InitializeObjectAttributes(&ObjectAttributes, 265 &SystemRoot, 266 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 267 NULL, NULL); 268 Status = ZwOpenFile(&SystemRootHandle, 269 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 270 &ObjectAttributes, 271 &IoStatusBlock, 272 FILE_SHARE_READ | FILE_SHARE_WRITE, 273 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 274 ok_eq_hex(Status, STATUS_SUCCESS); 275 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 276 if (Status == STATUS_SUCCESS) 277 { 278 IoStatusBlock.Status = 0xFFFFFFFF; 279 IoStatusBlock.Information = 0xFFFFFFFF; 280 InitializeObjectAttributes(&ObjectAttributes, 281 &Foobar, 282 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 283 SystemRootHandle, 284 NULL); 285 Status = IoCreateFile(&ParentHandle, 286 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 287 &ObjectAttributes, 288 &IoStatusBlock, 289 NULL, 290 0, 291 FILE_SHARE_READ | FILE_SHARE_WRITE, 292 FILE_OPEN, 293 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 294 NULL, 295 0, 296 CreateFileTypeNone, 297 NULL, 298 IO_OPEN_TARGET_DIRECTORY); 299 ok_eq_hex(Status, STATUS_SUCCESS); 300 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 301 if (Status == STATUS_SUCCESS) 302 { 303 Status = ObReferenceObjectByHandle(ParentHandle, 304 FILE_READ_DATA, 305 *IoFileObjectType, 306 KernelMode, 307 (PVOID *)&ParentFileObject, 308 NULL); 309 ok_eq_hex(Status, STATUS_SUCCESS); 310 if (Status == STATUS_SUCCESS) 311 { 312 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); 313 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); 314 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); 315 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); 316 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); 317 Status = ObReferenceObjectByHandle(SystemRootHandle, 318 FILE_READ_DATA, 319 *IoFileObjectType, 320 KernelMode, 321 (PVOID *)&SystemRootFileObject, 322 NULL); 323 ok_eq_hex(Status, STATUS_SUCCESS); 324 if (Status == STATUS_SUCCESS) 325 { 326 ok_eq_pointer(ParentFileObject->RelatedFileObject, SystemRootFileObject); 327 ok(ParentFileObject->RelatedFileObject != TargetFileObject, "File objects must be different\n"); 328 ok(SystemRootFileObject != TargetFileObject, "File objects must be different\n"); 329 ObDereferenceObject(SystemRootFileObject); 330 } 331 ObDereferenceObject(ParentFileObject); 332 } 333 ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST); 334 ObCloseHandle(ParentHandle, KernelMode); 335 } 336 ObCloseHandle(SystemRootHandle, KernelMode); 337 } 338 339 ObDereferenceObject(TargetFileObject); 340 ObCloseHandle(TargetHandle, KernelMode); 341 342 /* *** */ 343 344 /* Direct target open of something that doesn't exist */ 345 IoStatusBlock.Status = 0xFFFFFFFF; 346 IoStatusBlock.Information = 0xFFFFFFFF; 347 InitializeObjectAttributes(&ObjectAttributes, 348 &SystemRootFoobarFoobar, 349 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 350 NULL, NULL); 351 Status = IoCreateFile(&ParentHandle, 352 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 353 &ObjectAttributes, 354 &IoStatusBlock, 355 NULL, 356 0, 357 FILE_SHARE_READ | FILE_SHARE_WRITE, 358 FILE_OPEN, 359 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 360 NULL, 361 0, 362 CreateFileTypeNone, 363 NULL, 364 IO_OPEN_TARGET_DIRECTORY); 365 ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND); 366 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); 367 if (Status == STATUS_SUCCESS) 368 { 369 ObCloseHandle(ParentHandle, KernelMode); 370 } 371 372 /* Relative target open of something that doesn't exist */ 373 IoStatusBlock.Status = 0xFFFFFFFF; 374 IoStatusBlock.Information = 0xFFFFFFFF; 375 InitializeObjectAttributes(&ObjectAttributes, 376 &SystemRoot, 377 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 378 NULL, NULL); 379 Status = ZwOpenFile(&SystemRootHandle, 380 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 381 &ObjectAttributes, 382 &IoStatusBlock, 383 FILE_SHARE_READ | FILE_SHARE_WRITE, 384 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 385 ok_eq_hex(Status, STATUS_SUCCESS); 386 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 387 if (Status == STATUS_SUCCESS) 388 { 389 IoStatusBlock.Status = 0xFFFFFFFF; 390 IoStatusBlock.Information = 0xFFFFFFFF; 391 InitializeObjectAttributes(&ObjectAttributes, 392 &FoobarFoobar, 393 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 394 SystemRootHandle, 395 NULL); 396 Status = IoCreateFile(&ParentHandle, 397 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 398 &ObjectAttributes, 399 &IoStatusBlock, 400 NULL, 401 0, 402 FILE_SHARE_READ | FILE_SHARE_WRITE, 403 FILE_OPEN, 404 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 405 NULL, 406 0, 407 CreateFileTypeNone, 408 NULL, 409 IO_OPEN_TARGET_DIRECTORY); 410 ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND); 411 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); 412 if (Status == STATUS_SUCCESS) 413 { 414 ObCloseHandle(ParentHandle, KernelMode); 415 } 416 ObCloseHandle(SystemRootHandle, KernelMode); 417 } 418 } 419 420 static 421 VOID 422 NTAPI 423 TestSymlinks(VOID) 424 { 425 HANDLE ReparseHandle; 426 NTSTATUS Status; 427 IO_STATUS_BLOCK IoStatusBlock; 428 OBJECT_ATTRIBUTES ObjectAttributes; 429 PREPARSE_DATA_BUFFER Reparse; 430 FILE_DISPOSITION_INFORMATION ToDelete; 431 PFILE_OBJECT FileObject; 432 UNICODE_STRING SysDir, Foobar, Regedit; 433 ULONG Size; 434 435 /* Get Windows/ReactOS directory */ 436 InitializeObjectAttributes(&ObjectAttributes, 437 &SystemRoot, 438 OBJ_CASE_INSENSITIVE, 439 NULL, 440 NULL); 441 Status = ZwOpenFile(&ReparseHandle, 442 FILE_READ_DATA, 443 &ObjectAttributes, 444 &IoStatusBlock, 445 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 446 FILE_DIRECTORY_FILE); 447 if (skip(NT_SUCCESS(Status), "Opening \\SystemRoot failed: %lx\n", Status)) 448 { 449 return; 450 } 451 452 Status = ObReferenceObjectByHandle(ReparseHandle, 453 FILE_READ_DATA, 454 *IoFileObjectType, 455 UserMode, 456 (PVOID *)&FileObject, 457 NULL); 458 if (skip(NT_SUCCESS(Status), "Querying name failed: %lx\n", Status)) 459 { 460 ZwClose(ReparseHandle); 461 return; 462 } 463 464 SysDir.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\??\\C:")); 465 if (skip(SysDir.Buffer != NULL, "Allocating memory failed\n")) 466 { 467 ObDereferenceObject(FileObject); 468 ZwClose(ReparseHandle); 469 return; 470 } 471 472 SysDir.Length = sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL); 473 SysDir.MaximumLength = FileObject->FileName.Length + sizeof(L"\\??\\C:"); 474 RtlCopyMemory(SysDir.Buffer, L"\\??\\C:", sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL)); 475 RtlAppendUnicodeStringToString(&SysDir, &FileObject->FileName); 476 477 Foobar.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\foobar.exe")); 478 if (skip(Foobar.Buffer != NULL, "Allocating memory failed\n")) 479 { 480 ExFreePool(SysDir.Buffer); 481 ObDereferenceObject(FileObject); 482 ZwClose(ReparseHandle); 483 return; 484 } 485 486 Foobar.Length = 0; 487 Foobar.MaximumLength = FileObject->FileName.Length + sizeof(L"\\foobar.exe"); 488 RtlCopyUnicodeString(&Foobar, &FileObject->FileName); 489 RtlCopyMemory(&Foobar.Buffer[Foobar.Length / sizeof(WCHAR)], L"\\foobar.exe", sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL)); 490 Foobar.Length += (sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL)); 491 492 Regedit.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\regedit.exe")); 493 if (skip(Regedit.Buffer != NULL, "Allocating memory failed\n")) 494 { 495 ExFreePool(Foobar.Buffer); 496 ExFreePool(SysDir.Buffer); 497 ObDereferenceObject(FileObject); 498 ZwClose(ReparseHandle); 499 return; 500 } 501 502 Regedit.Length = 0; 503 Regedit.MaximumLength = FileObject->FileName.Length + sizeof(L"\\regedit.exe"); 504 RtlCopyUnicodeString(&Regedit, &FileObject->FileName); 505 RtlCopyMemory(&Regedit.Buffer[Regedit.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); 506 Regedit.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); 507 508 ObDereferenceObject(FileObject); 509 ZwClose(ReparseHandle); 510 511 ToDelete.DeleteFile = TRUE; 512 Size = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL); 513 514 InitializeObjectAttributes(&ObjectAttributes, 515 &SystemRootFoobar, 516 OBJ_CASE_INSENSITIVE, 517 NULL, 518 NULL); 519 Status = ZwCreateFile(&ReparseHandle, 520 GENERIC_READ | GENERIC_WRITE | DELETE, 521 &ObjectAttributes, 522 &IoStatusBlock, 523 NULL, 524 FILE_ATTRIBUTE_NORMAL, 525 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 526 FILE_SUPERSEDE, 527 FILE_NON_DIRECTORY_FILE, 528 NULL, 529 0); 530 ok_eq_hex(Status, STATUS_SUCCESS); 531 if (skip(NT_SUCCESS(Status), "Creating file failed: %lx\n", Status)) 532 { 533 ExFreePool(Regedit.Buffer); 534 ExFreePool(Foobar.Buffer); 535 ExFreePool(SysDir.Buffer); 536 return; 537 } 538 539 Reparse = ExAllocatePool(NonPagedPool, Size); 540 RtlZeroMemory(Reparse, Size); 541 Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK; 542 Reparse->ReparseDataLength = 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL); 543 Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL); 544 Reparse->SymbolicLinkReparseBuffer.PrintNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(L"\\??\\"); 545 Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset = Reparse->SymbolicLinkReparseBuffer.PrintNameLength; 546 RtlCopyMemory(Reparse->SymbolicLinkReparseBuffer.PathBuffer, 547 (WCHAR *)((ULONG_PTR)SysDir.Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL)), 548 SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL)); 549 RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL)), 550 L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); 551 RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset), 552 SysDir.Buffer, SysDir.Length); 553 RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset + SysDir.Length), 554 L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); 555 556 Status = ZwFsControlFile(ReparseHandle, 557 NULL, 558 NULL, 559 NULL, 560 &IoStatusBlock, 561 FSCTL_SET_REPARSE_POINT, 562 Reparse, 563 Size, 564 NULL, 565 0); 566 ok_eq_hex(Status, STATUS_SUCCESS); 567 if (!NT_SUCCESS(Status)) 568 { 569 ZwClose(ReparseHandle); 570 571 Status = ZwCreateFile(&ReparseHandle, 572 FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE, 573 &ObjectAttributes, 574 &IoStatusBlock, 575 NULL, 576 FILE_ATTRIBUTE_NORMAL, 577 0, 578 FILE_SUPERSEDE, 579 FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, 580 NULL, 581 0); 582 if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status)) 583 { 584 Status = ZwOpenFile(&ReparseHandle, 585 DELETE, 586 &ObjectAttributes, 587 &IoStatusBlock, 588 FILE_SHARE_DELETE, 589 FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE); 590 ok_eq_hex(Status, STATUS_SUCCESS); 591 ZwClose(ReparseHandle); 592 ExFreePool(Regedit.Buffer); 593 ExFreePool(Foobar.Buffer); 594 ExFreePool(SysDir.Buffer); 595 ExFreePool(Reparse); 596 return; 597 } 598 599 Status = ZwFsControlFile(ReparseHandle, 600 NULL, 601 NULL, 602 NULL, 603 &IoStatusBlock, 604 FSCTL_SET_REPARSE_POINT, 605 Reparse, 606 Size, 607 NULL, 608 0); 609 } 610 611 if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status)) 612 { 613 ZwSetInformationFile(ReparseHandle, 614 &IoStatusBlock, 615 &ToDelete, 616 sizeof(ToDelete), 617 FileDispositionInformation); 618 ZwClose(ReparseHandle); 619 ExFreePool(Regedit.Buffer); 620 ExFreePool(Foobar.Buffer); 621 ExFreePool(SysDir.Buffer); 622 ExFreePool(Reparse); 623 return; 624 } 625 626 ZwClose(ReparseHandle); 627 628 Status = ZwCreateFile(&ReparseHandle, 629 GENERIC_READ, 630 &ObjectAttributes, 631 &IoStatusBlock, 632 NULL, 633 FILE_ATTRIBUTE_NORMAL, 634 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 635 FILE_OPEN, 636 FILE_NON_DIRECTORY_FILE, 637 NULL, 638 0); 639 ok(Status == STATUS_SUCCESS || /* Windows Vista+ */ 640 Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */ 641 "ZwCreateFile returned unexpected status: %lx\n", Status); 642 if (NT_SUCCESS(Status)) 643 { 644 Status = ObReferenceObjectByHandle(ReparseHandle, 645 FILE_READ_DATA, 646 *IoFileObjectType, 647 UserMode, 648 (PVOID *)&FileObject, 649 NULL); 650 ok_eq_hex(Status, STATUS_SUCCESS); 651 if (NT_SUCCESS(Status)) 652 { 653 ok(RtlCompareUnicodeString(&Regedit, &FileObject->FileName, TRUE) == 0, 654 "Expected: %wZ. Opened: %wZ\n", &Regedit, &FileObject->FileName); 655 ObDereferenceObject(FileObject); 656 } 657 658 ZwClose(ReparseHandle); 659 } 660 661 ExFreePool(Regedit.Buffer); 662 663 Status = IoCreateFile(&ReparseHandle, 664 GENERIC_READ, 665 &ObjectAttributes, 666 &IoStatusBlock, 667 NULL, 668 FILE_ATTRIBUTE_NORMAL, 669 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 670 FILE_OPEN, 671 FILE_NON_DIRECTORY_FILE, 672 NULL, 673 0, 674 CreateFileTypeNone, 675 NULL, 676 IO_NO_PARAMETER_CHECKING | IO_STOP_ON_SYMLINK); 677 ok(Status == STATUS_STOPPED_ON_SYMLINK || /* Windows Vista+ */ 678 Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */ 679 "ZwCreateFile returned unexpected status: %lx\n", Status); 680 if (NT_SUCCESS(Status)) 681 { 682 ZwClose(ReparseHandle); 683 } 684 685 Status = ZwCreateFile(&ReparseHandle, 686 GENERIC_READ | GENERIC_WRITE | DELETE, 687 &ObjectAttributes, 688 &IoStatusBlock, 689 NULL, 690 FILE_ATTRIBUTE_NORMAL, 691 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 692 FILE_OPEN, 693 FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, 694 NULL, 695 0); 696 if (skip(NT_SUCCESS(Status), "Creating opening reparse point: %lx\n", Status)) 697 { 698 Status = ZwOpenFile(&ReparseHandle, 699 DELETE, 700 &ObjectAttributes, 701 &IoStatusBlock, 702 FILE_SHARE_DELETE, 703 FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE); 704 ok_eq_hex(Status, STATUS_SUCCESS); 705 ZwClose(ReparseHandle); 706 ExFreePool(Foobar.Buffer); 707 ExFreePool(SysDir.Buffer); 708 ExFreePool(Reparse); 709 return; 710 } 711 712 Status = ObReferenceObjectByHandle(ReparseHandle, 713 FILE_READ_DATA, 714 *IoFileObjectType, 715 UserMode, 716 (PVOID *)&FileObject, 717 NULL); 718 ok_eq_hex(Status, STATUS_SUCCESS); 719 if (NT_SUCCESS(Status)) 720 { 721 ok(RtlCompareUnicodeString(&Foobar, &FileObject->FileName, TRUE) == 0, 722 "Expected: %wZ. Opened: %wZ\n", &Foobar, &FileObject->FileName); 723 ObDereferenceObject(FileObject); 724 } 725 726 ExFreePool(Foobar.Buffer); 727 728 RtlZeroMemory(Reparse, Size); 729 Status = ZwFsControlFile(ReparseHandle, 730 NULL, 731 NULL, 732 NULL, 733 &IoStatusBlock, 734 FSCTL_GET_REPARSE_POINT, 735 NULL, 736 0, 737 Reparse, 738 Size); 739 ok_eq_hex(Status, STATUS_SUCCESS); 740 ok_eq_hex(IoStatusBlock.Information, Size); 741 if (NT_SUCCESS(Status)) 742 { 743 PWSTR Buffer; 744 UNICODE_STRING ReparsePath, FullPath; 745 746 ok_eq_hex(Reparse->ReparseTag, IO_REPARSE_TAG_SYMLINK); 747 ok_eq_hex(Reparse->ReparseDataLength, 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); 748 ok_eq_hex(Reparse->SymbolicLinkReparseBuffer.Flags, 0); 749 750 FullPath.Length = 0; 751 FullPath.MaximumLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL); 752 Buffer = FullPath.Buffer = ExAllocatePool(NonPagedPool, FullPath.MaximumLength); 753 if (!skip(Buffer != NULL, "Memory allocation failed!\n")) 754 { 755 RtlCopyUnicodeString(&FullPath, &SysDir); 756 RtlCopyMemory(&FullPath.Buffer[FullPath.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); 757 FullPath.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); 758 ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset); 759 ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength; 760 ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath); 761 762 FullPath.Length -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); 763 FullPath.MaximumLength -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); 764 FullPath.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); 765 ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.PrintNameOffset); 766 ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.PrintNameLength; 767 ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath); 768 769 ExFreePool(Buffer); 770 } 771 } 772 773 ExFreePool(SysDir.Buffer); 774 ExFreePool(Reparse); 775 776 ZwSetInformationFile(ReparseHandle, 777 &IoStatusBlock, 778 &ToDelete, 779 sizeof(ToDelete), 780 FileDispositionInformation); 781 ZwClose(ReparseHandle); 782 } 783 784 //static 785 VOID 786 NTAPI 787 UserModeTest(VOID) 788 { 789 NTSTATUS Status; 790 IO_STATUS_BLOCK IoStatusBlock; 791 OBJECT_ATTRIBUTES ObjectAttributes; 792 HANDLE ParentHandle, SystemRootHandle; 793 794 ok(ExGetPreviousMode() == UserMode, "KernelMode returned!\n"); 795 796 /* Attempt direct target open */ 797 IoStatusBlock.Status = 0xFFFFFFFF; 798 IoStatusBlock.Information = 0xFFFFFFFF; 799 InitializeObjectAttributes(&ObjectAttributes, 800 &SystemRootRegedit, 801 OBJ_CASE_INSENSITIVE, 802 NULL, NULL); 803 Status = IoCreateFile(&ParentHandle, 804 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 805 &ObjectAttributes, 806 &IoStatusBlock, 807 NULL, 808 0, 809 FILE_SHARE_READ | FILE_SHARE_WRITE, 810 FILE_OPEN, 811 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 812 NULL, 813 0, 814 CreateFileTypeNone, 815 NULL, 816 IO_OPEN_TARGET_DIRECTORY); 817 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); 818 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); 819 if (Status == STATUS_SUCCESS) 820 { 821 ObCloseHandle(ParentHandle, UserMode); 822 } 823 824 /* Attempt relative target open */ 825 IoStatusBlock.Status = 0xFFFFFFFF; 826 IoStatusBlock.Information = 0xFFFFFFFF; 827 InitializeObjectAttributes(&ObjectAttributes, 828 &SystemRoot, 829 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 830 NULL, NULL); 831 Status = ZwOpenFile(&SystemRootHandle, 832 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 833 &ObjectAttributes, 834 &IoStatusBlock, 835 FILE_SHARE_READ | FILE_SHARE_WRITE, 836 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 837 ok_eq_hex(Status, STATUS_SUCCESS); 838 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); 839 if (Status == STATUS_SUCCESS) 840 { 841 IoStatusBlock.Status = 0xFFFFFFFF; 842 IoStatusBlock.Information = 0xFFFFFFFF; 843 InitializeObjectAttributes(&ObjectAttributes, 844 &Regedit, 845 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 846 SystemRootHandle, 847 NULL); 848 Status = IoCreateFile(&ParentHandle, 849 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, 850 &ObjectAttributes, 851 &IoStatusBlock, 852 NULL, 853 0, 854 FILE_SHARE_READ | FILE_SHARE_WRITE, 855 FILE_OPEN, 856 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 857 NULL, 858 0, 859 CreateFileTypeNone, 860 NULL, 861 IO_OPEN_TARGET_DIRECTORY); 862 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); 863 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); 864 if (Status == STATUS_SUCCESS) 865 { 866 ObCloseHandle(ParentHandle, KernelMode); 867 } 868 ObCloseHandle(SystemRootHandle, KernelMode); 869 } 870 } 871 872 START_TEST(IoCreateFile) 873 { 874 PKTHREAD ThreadHandle; 875 876 TestSymlinks(); 877 878 /* Justify the next comment/statement */ 879 UserModeTest(); 880 881 /* We've to be in kernel mode, so spawn a thread */ 882 ThreadHandle = KmtStartThread(KernelModeTest, NULL); 883 KmtFinishThread(ThreadHandle, NULL); 884 } 885