diff options
| author | tumagonx | 2017-08-08 10:54:53 +0700 |
|---|---|---|
| committer | tumagonx | 2017-08-08 10:54:53 +0700 |
| commit | 2acec63b2ed75bf4b71ad257db573c4b8f9639e7 (patch) | |
| tree | a8bea139ddd26116d44ea182b0b8436f2162e6e3 /media.c | |
initial commit
Diffstat (limited to 'media.c')
| -rw-r--r-- | media.c | 444 |
1 files changed, 444 insertions, 0 deletions
| @@ -0,0 +1,444 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2004 Security Architects Corporation. All rights reserved. | ||
| 3 | * | ||
| 4 | * Module Name: | ||
| 5 | * | ||
| 6 | * media.c | ||
| 7 | * | ||
| 8 | * Abstract: | ||
| 9 | * | ||
| 10 | * This module deals with removable media drives. Removable media drives can be made read-only | ||
| 11 | * or disabled altogether. | ||
| 12 | * | ||
| 13 | * Addition of removable drives is detected by monitoring the creation new drive symbolic links. | ||
| 14 | * Drive removal is detected by receiving Plug-and-Play notification. | ||
| 15 | * | ||
| 16 | * Note: Plug-and-Play notifications are not used to detect addition of removable drives since | ||
| 17 | * drive letters are not yet assigned when notifications arrive. | ||
| 18 | * | ||
| 19 | * Author: | ||
| 20 | * | ||
| 21 | * Eugene Tsyrklevich 02-Jun-2004 | ||
| 22 | */ | ||
| 23 | |||
| 24 | |||
| 25 | #include <NTDDK.h> | ||
| 26 | |||
| 27 | #undef DEFINE_GUID | ||
| 28 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name \ | ||
| 29 | = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } | ||
| 30 | |||
| 31 | #include <ntddstor.h> | ||
| 32 | #include <wdmguid.h> | ||
| 33 | #include "media.h" | ||
| 34 | #include "pathproc.h" | ||
| 35 | #include "policy.h" | ||
| 36 | |||
| 37 | |||
| 38 | #ifdef ALLOC_PRAGMA | ||
| 39 | #pragma alloc_text (INIT, InitRemovableMediaHooks) | ||
| 40 | #pragma alloc_text (PAGE, RemoveRemovableMediaHooks) | ||
| 41 | #endif | ||
| 42 | |||
| 43 | |||
| 44 | //XXX investigate IoRegisterFsRegistrationChange | ||
| 45 | //reference: www.pulsetrainsw.com/articlesitem.asp?id=3 | ||
| 46 | |||
| 47 | PVOID DiskNotificationEntry = NULL, CdromNotificationEntry = NULL; | ||
| 48 | |||
| 49 | /* removable media flags defined in drive.h (READONLY, etc) */ | ||
| 50 | UCHAR MediaRemovableFlags = 0; | ||
| 51 | |||
| 52 | |||
| 53 | typedef struct _WORK_CONTEXT | ||
| 54 | { | ||
| 55 | PIO_WORKITEM Item; | ||
| 56 | UNICODE_STRING SymbolicLinkName; | ||
| 57 | |||
| 58 | } WORK_CONTEXT, *PWORK_CONTEXT; | ||
| 59 | |||
| 60 | |||
| 61 | |||
| 62 | /* | ||
| 63 | * AddDrive() | ||
| 64 | * | ||
| 65 | * Description: | ||
| 66 | * Create policy access rules for removable drives as they are added at runtime. | ||
| 67 | * | ||
| 68 | * Parameters: | ||
| 69 | * pusDriveName - . | ||
| 70 | * DriveLetter - Letter of the drive being added. | ||
| 71 | * | ||
| 72 | * Returns: | ||
| 73 | * Nothing. | ||
| 74 | */ | ||
| 75 | |||
| 76 | VOID | ||
| 77 | AddDrive(PUNICODE_STRING pusDriveName, CHAR DriveLetter) | ||
| 78 | { | ||
| 79 | PDEVICE_OBJECT pDeviceObject; | ||
| 80 | PFILE_OBJECT fo; | ||
| 81 | NTSTATUS rc; | ||
| 82 | |||
| 83 | |||
| 84 | rc = IoGetDeviceObjectPointer(pusDriveName, FILE_READ_ATTRIBUTES, &fo, &pDeviceObject); | ||
| 85 | if (! NT_SUCCESS(rc)) | ||
| 86 | { | ||
| 87 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_VERBOSE, ("AddDrive: IoGetDeviceObjectPointer failed with status %x\n", rc)); | ||
| 88 | return; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive(%S): %d\n", pusDriveName->Buffer, pDeviceObject->Characteristics)); | ||
| 93 | |||
| 94 | |||
| 95 | if (pDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) | ||
| 96 | { | ||
| 97 | CHAR rule[MAX_PATH]; | ||
| 98 | |||
| 99 | |||
| 100 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("AddDrive: removable drive! %c: %S\n", DriveLetter, pusDriveName->Buffer)); | ||
| 101 | |||
| 102 | |||
| 103 | /* Create a new global policy rule */ | ||
| 104 | |||
| 105 | if (IS_REMOVABLE_MEDIA_DISABLED()) | ||
| 106 | { | ||
| 107 | sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny"); | ||
| 108 | |||
| 109 | PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "all", rule); | ||
| 110 | |||
| 111 | /* no need to process other rules, this one denies everything already */ | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | |||
| 115 | if (IS_REMOVABLE_MEDIA_READONLY() /*&& !(pDeviceObject->Characteristics & FILE_READ_ONLY_DEVICE)*/) | ||
| 116 | { | ||
| 117 | sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny"); | ||
| 118 | |||
| 119 | PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "write", rule); | ||
| 120 | } | ||
| 121 | |||
| 122 | if (IS_REMOVABLE_MEDIA_NOEXECUTE()) | ||
| 123 | { | ||
| 124 | sprintf(rule, "name match \"%c:\\*\" then %s", DriveLetter, "deny"); | ||
| 125 | |||
| 126 | PolicyParseObjectRule(&gSecPolicy, RULE_FILE, "execute", rule); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | |||
| 131 | return; | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | |||
| 136 | /* | ||
| 137 | * RemoveDrive() | ||
| 138 | * | ||
| 139 | * Description: | ||
| 140 | * . | ||
| 141 | * | ||
| 142 | * Parameters: | ||
| 143 | * pusDriveName - . | ||
| 144 | * | ||
| 145 | * Returns: | ||
| 146 | * Nothing. | ||
| 147 | */ | ||
| 148 | |||
| 149 | VOID | ||
| 150 | RemoveDrive(PUNICODE_STRING pusDriveName) | ||
| 151 | { | ||
| 152 | PDEVICE_OBJECT pDeviceObject; | ||
| 153 | PFILE_OBJECT fo; | ||
| 154 | NTSTATUS rc; | ||
| 155 | |||
| 156 | |||
| 157 | rc = IoGetDeviceObjectPointer(pusDriveName, FILE_READ_ATTRIBUTES, &fo, &pDeviceObject); | ||
| 158 | if (! NT_SUCCESS(rc)) | ||
| 159 | { | ||
| 160 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: IoGetDeviceObjectPointer failed with status %x\n", rc)); | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | |||
| 164 | |||
| 165 | if (pDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) | ||
| 166 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: removable drive! %S\n", pusDriveName->Buffer)); | ||
| 167 | |||
| 168 | |||
| 169 | // rc = RtlVolumeDeviceToDosName(pDeviceObject, pusDriveName); | ||
| 170 | // if (NT_SUCCESS(rc)) | ||
| 171 | // LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveDrive: IoVolumeDeviceToDosName returned %S\n", pusDriveName->Buffer)); | ||
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | |||
| 176 | /* | ||
| 177 | * MonitorDriveLinks() | ||
| 178 | * | ||
| 179 | * Description: | ||
| 180 | * This routine is called from HookedNtCreateSymbolicLinkObject whenever a new symbolic link is created. | ||
| 181 | * ProcessDriveLink is responsible for monitoring the creation of any new media drives. When a new removable | ||
| 182 | * media drive is added to a system, a new symbolic link "\GLOBAL??\X:" is created (where X is the | ||
| 183 | * assigned drive letter). | ||
| 184 | * | ||
| 185 | * Note: We are not interested in creation of "fake" drives (i.e. subst c: z:\) since those will be | ||
| 186 | * correctly resolved by symbolic link name resolution code (policy enforcement). "Fake" drives | ||
| 187 | * are added in userland and come up as "\??\X:". | ||
| 188 | * | ||
| 189 | * Parameters: | ||
| 190 | * Link - created symbolic link name. | ||
| 191 | * | ||
| 192 | * Returns: | ||
| 193 | * Nothing. | ||
| 194 | */ | ||
| 195 | |||
| 196 | VOID | ||
| 197 | MonitorDriveLinks(const PCHAR Link) | ||
| 198 | { | ||
| 199 | CHAR DriveLetter; | ||
| 200 | ANSI_STRING AnsiString; | ||
| 201 | UNICODE_STRING UnicodeString; | ||
| 202 | int len = strlen(Link); | ||
| 203 | |||
| 204 | |||
| 205 | /* match \GLOBAL??\Z: && \??\Z: drive references */ | ||
| 206 | if (len == 12 && (strncmp(Link, "\\GLOBAL??\\", 10) == 0) && isalpha(Link[10]) && Link[11] == ':') | ||
| 207 | { | ||
| 208 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: matched \\global??\\. letter %c\n", Link[10])); | ||
| 209 | |||
| 210 | DriveLetter = Link[10]; | ||
| 211 | } | ||
| 212 | else if (len == 6 && (strncmp(Link, "\\??\\", 4) == 0) && isalpha(Link[4]) && Link[5] == ':') | ||
| 213 | { | ||
| 214 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: matched \\??\\. letter %c\n", Link[4])); | ||
| 215 | |||
| 216 | DriveLetter = Link[4]; | ||
| 217 | } | ||
| 218 | else | ||
| 219 | { | ||
| 220 | return; | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | RtlInitAnsiString(&AnsiString, Link); | ||
| 225 | |||
| 226 | if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE))) | ||
| 227 | { | ||
| 228 | AddDrive(&UnicodeString, DriveLetter); | ||
| 229 | |||
| 230 | RtlFreeUnicodeString(&UnicodeString); | ||
| 231 | } | ||
| 232 | else | ||
| 233 | { | ||
| 234 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("MonitorDriveLinks: failed to convert %s\n", Link)); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | |||
| 240 | /* | ||
| 241 | * PnpWorker() | ||
| 242 | * | ||
| 243 | * Description: | ||
| 244 | * A work item routine that runs at PASSIVE_LEVEL irql. The routine is scheduled by PnpCallback | ||
| 245 | * which is not allowed to block. | ||
| 246 | * | ||
| 247 | * PnpWorker calls RemoveDrive() with a drive name setup by PnpCallback. | ||
| 248 | * | ||
| 249 | * Parameters: | ||
| 250 | * pDeviceObject - . | ||
| 251 | * Context - . | ||
| 252 | * | ||
| 253 | * Returns: | ||
| 254 | * Nothing. | ||
| 255 | */ | ||
| 256 | |||
| 257 | VOID | ||
| 258 | PnpWorker(IN PDEVICE_OBJECT pDeviceObject, IN PVOID Context) | ||
| 259 | { | ||
| 260 | PWORK_CONTEXT WorkContext = (PWORK_CONTEXT) Context; | ||
| 261 | |||
| 262 | |||
| 263 | if (WorkContext == NULL) | ||
| 264 | { | ||
| 265 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: WorkContext = NULL\n")); | ||
| 266 | return; | ||
| 267 | } | ||
| 268 | |||
| 269 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("PnpWorker: %S\n", WorkContext->SymbolicLinkName.Buffer)); | ||
| 270 | |||
| 271 | |||
| 272 | RemoveDrive(&WorkContext->SymbolicLinkName); | ||
| 273 | |||
| 274 | |||
| 275 | IoFreeWorkItem(WorkContext->Item); | ||
| 276 | |||
| 277 | ExFreePoolWithTag(WorkContext, _POOL_TAG); | ||
| 278 | } | ||
| 279 | |||
| 280 | |||
| 281 | |||
| 282 | /* | ||
| 283 | * PnpCallback() | ||
| 284 | * | ||
| 285 | * Description: | ||
| 286 | * Plug-and-Play callback. Gets called when a p-n-p drive/cdrom interface is modified | ||
| 287 | * (i.e. when a removable drive is added or removed from the system). | ||
| 288 | * | ||
| 289 | * Parameters: | ||
| 290 | * NotificationStructure - DEVICE_INTERFACE_CHANGE_NOTIFICATION indicating which interface changed. | ||
| 291 | * Context - the driver's device context. | ||
| 292 | * | ||
| 293 | * Returns: | ||
| 294 | * STATUS_SUCCESS. | ||
| 295 | */ | ||
| 296 | |||
| 297 | NTSTATUS | ||
| 298 | PnpCallback(IN PVOID NotificationStructure, IN PVOID Context) | ||
| 299 | { | ||
| 300 | PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notify = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure; | ||
| 301 | PDEVICE_OBJECT pDeviceObject = (PDEVICE_OBJECT) Context; | ||
| 302 | PIO_WORKITEM WorkItem; | ||
| 303 | PWORK_CONTEXT WorkContext; | ||
| 304 | |||
| 305 | |||
| 306 | if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL)) | ||
| 307 | { | ||
| 308 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_REMOVAL %S\n", Notify->SymbolicLinkName->Buffer)); | ||
| 309 | /* | ||
| 310 | } | ||
| 311 | |||
| 312 | |||
| 313 | if (IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_ARRIVAL) || | ||
| 314 | IsEqualGUID((LPGUID) &Notify->Event, (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL)) | ||
| 315 | { | ||
| 316 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("GUID_DEVICE_INTERFACE_ARRIVAL %x %S\n", Notify->SymbolicLinkName, Notify->SymbolicLinkName->Buffer)); | ||
| 317 | */ | ||
| 318 | |||
| 319 | /* | ||
| 320 | * Schedule a work item to process this request. Cannot block in this callback function. | ||
| 321 | */ | ||
| 322 | |||
| 323 | WorkItem = IoAllocateWorkItem(pDeviceObject); | ||
| 324 | |||
| 325 | WorkContext = (PWORK_CONTEXT) ExAllocatePoolWithTag(PagedPool, | ||
| 326 | sizeof(WORK_CONTEXT) + Notify->SymbolicLinkName->Length, | ||
| 327 | _POOL_TAG); | ||
| 328 | if (!WorkContext) | ||
| 329 | { | ||
| 330 | IoFreeWorkItem(WorkItem); | ||
| 331 | return(STATUS_SUCCESS); | ||
| 332 | } | ||
| 333 | |||
| 334 | WorkContext->SymbolicLinkName.Buffer = (PWSTR) ((PCHAR) &WorkContext->SymbolicLinkName + sizeof(UNICODE_STRING)); | ||
| 335 | WorkContext->SymbolicLinkName.MaximumLength = Notify->SymbolicLinkName->Length; | ||
| 336 | WorkContext->SymbolicLinkName.Length = 0; | ||
| 337 | |||
| 338 | WorkContext->Item = WorkItem; | ||
| 339 | RtlCopyUnicodeString(&WorkContext->SymbolicLinkName, Notify->SymbolicLinkName); | ||
| 340 | |||
| 341 | IoQueueWorkItem(WorkItem, PnpWorker, DelayedWorkQueue, WorkContext); | ||
| 342 | } | ||
| 343 | |||
| 344 | |||
| 345 | return STATUS_SUCCESS; | ||
| 346 | } | ||
| 347 | |||
| 348 | |||
| 349 | |||
| 350 | /* | ||
| 351 | * InitRemovableMediaHooks() | ||
| 352 | * | ||
| 353 | * Description: | ||
| 354 | * Process any existing drives and register Plug-and-Play notifications for future drive additions/removals. | ||
| 355 | * | ||
| 356 | * NOTE: Called once during driver initialization (DriverEntry()). | ||
| 357 | * | ||
| 358 | * Parameters: | ||
| 359 | * None. | ||
| 360 | * | ||
| 361 | * Returns: | ||
| 362 | * TRUE to indicate success, FALSE if failed. | ||
| 363 | */ | ||
| 364 | |||
| 365 | BOOLEAN | ||
| 366 | InitRemovableMediaHooks(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pDeviceObject) | ||
| 367 | { | ||
| 368 | UNICODE_STRING Name; | ||
| 369 | WCHAR Buffer[MAX_PATH] = L"\\??\\A:"; | ||
| 370 | NTSTATUS rc; | ||
| 371 | HANDLE hLink; | ||
| 372 | OBJECT_ATTRIBUTES oa; | ||
| 373 | char DriveLetter; | ||
| 374 | |||
| 375 | |||
| 376 | for (DriveLetter = 'A'; DriveLetter <= 'Z'; DriveLetter++) | ||
| 377 | { | ||
| 378 | Buffer[4] = DriveLetter; | ||
| 379 | |||
| 380 | RtlInitUnicodeString(&Name, Buffer); | ||
| 381 | |||
| 382 | AddDrive(&Name, DriveLetter); | ||
| 383 | } | ||
| 384 | |||
| 385 | |||
| 386 | rc = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, | ||
| 387 | 0,//PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, | ||
| 388 | (LPGUID) &GUID_DEVINTERFACE_DISK, | ||
| 389 | pDriverObject, | ||
| 390 | PnpCallback, | ||
| 391 | pDeviceObject, | ||
| 392 | &DiskNotificationEntry); | ||
| 393 | |||
| 394 | if (! NT_SUCCESS(rc)) | ||
| 395 | { | ||
| 396 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("InitRemovableMediaHooks: IoRegisterPlugPlayNotification failed with status %x\n", rc)); | ||
| 397 | return FALSE; | ||
| 398 | } | ||
| 399 | |||
| 400 | |||
| 401 | rc = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, | ||
| 402 | 0,//PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, | ||
| 403 | (LPGUID) &GUID_DEVINTERFACE_CDROM, | ||
| 404 | pDriverObject, | ||
| 405 | PnpCallback, | ||
| 406 | pDeviceObject, | ||
| 407 | &CdromNotificationEntry); | ||
| 408 | |||
| 409 | if (! NT_SUCCESS(rc)) | ||
| 410 | { | ||
| 411 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("InitRemovableMediaHooks: IoRegisterPlugPlayNotification2 failed with status %x\n", rc)); | ||
| 412 | return FALSE; | ||
| 413 | } | ||
| 414 | |||
| 415 | |||
| 416 | return TRUE; | ||
| 417 | } | ||
| 418 | |||
| 419 | |||
| 420 | |||
| 421 | /* | ||
| 422 | * RemoveRemovableMediaHooks() | ||
| 423 | * | ||
| 424 | * Description: | ||
| 425 | * Unregister Plug-and-Play notifications. | ||
| 426 | * | ||
| 427 | * Parameters: | ||
| 428 | * None. | ||
| 429 | * | ||
| 430 | * Returns: | ||
| 431 | * Nothing. | ||
| 432 | */ | ||
| 433 | |||
| 434 | VOID | ||
| 435 | RemoveRemovableMediaHooks() | ||
| 436 | { | ||
| 437 | if (DiskNotificationEntry) | ||
| 438 | if (! NT_SUCCESS(IoUnregisterPlugPlayNotification(DiskNotificationEntry))) | ||
| 439 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveRemovableMediaHooks: IoUnregisterPlugPlayNotification failed\n")); | ||
| 440 | |||
| 441 | if (CdromNotificationEntry) | ||
| 442 | if (! NT_SUCCESS(IoUnregisterPlugPlayNotification(CdromNotificationEntry))) | ||
| 443 | LOG(LOG_SS_DRIVE, LOG_PRIORITY_DEBUG, ("RemoveRemovableMediaHooks: IoUnregisterPlugPlayNotification2 failed\n")); | ||
| 444 | } | ||
