Skip to content

File activity (kernel file I/O ETW)

This source records completed file creates, writes, renames, deletes and metadata changes. Each event is attributed to the process that issued it.

Collector ID freedr.file-etw
Windows mechanism Classic kernel FileIo provider ({90CBDC39-4A3E-11D1-84F4-0000F80464E3}) in the shared FreeDR-Unified system logger. Kernel flags DISK_IO, DISK_FILE_IO, FILE_IO, FILE_IO_INIT.
Hunt events view, event_type LIKE 'file.%'
Rule SQL source name file_etw
Hot table file_etw_v5
Code crates/freedr-collect-file-etw

Raw events use two 256 MiB-maximum rings: a control lane (name, cleanup, close, set-info, delete, rename, operation-end) and a bulk lane (create, write). See ring buffers.

Completed-operation model

FreeDR does not store raw I/O requests. Each request (Create, Write, SetInfo, Delete, Rename) is matched to its OperationEnd event by IRP pointer. The source keeps the request only when Windows reports that it completed.

Rule Detail
Matching deadline 30 s. Correlation state is bounded (about 2,000,000 entries / about 1 GiB).
Opens of existing files An open with FILE_OPEN disposition, or a create that only opened an existing file, updates the path cache and is not stored
Create results kept Superseded, created, overwritten
Failed or unknown outcome Not stored, except writes, which have no status
SetInfo Kept only for mutation information classes (32 classes, for example rename, disposition, basic info/timestamps, end-of-file). SetInfo from PID 4 (System) is dropped.
Reads Not collected. The read opcode is rejected at the callback.
Short-window compaction Repeats of the same kind, process and target within 1 s (writes) or 500 ms (other kinds) are merged before storage

Event types

event_type Produced Notes
file.create_open Yes The created column is 1 only when the file was newly created (FILE_CREATED)
file.write Yes byte_offset, byte_count of the first write in the window
file.rename Yes See gaps
file.delete Yes
file.set_info Yes Mutation classes only
file.read No Registered but never produced

file.name, file.operation_end, file.cleanup and file.close are internal and never stored.

Columns

Column Notes
pid Attributed process. NULL when attribution was not proven.
created 0/1 (see above)
path Drive-letter path, or the raw device path if it cannot be normalized
byte_offset, byte_count Writes only
old_path, volume_serial, file_id Present in the schema but always NULL in the current version
actor_image_path, actor_command_line, actor_start_at, actor_user_sid, actor_user_name Lineage of the attributed process

Process attribution (TTID resolver)

The FileIo provider reports the issuing thread ID (TTID). FreeDR does not trust the ETW header process ID for file events. It resolves the thread instead:

  1. Thread history. The process source maintains a history of thread lifetimes from thread start, stop and rundown events. A file event is attributed to the live thread with that TID if it started before the event. Otherwise it is attributed to a thread lifetime that stopped within the last 10 s and whose [start, stop] covers the event time. At most two lifetimes are kept per TID, so memory follows thread churn, not uptime.
  2. Hold. The thread history comes from a different ETW session and can arrive late. A request whose TID is still unknown is held for up to 2 s (order preserved) and retried.
  3. One OS check. If the TID is still unknown, FreeDR calls OpenThread once. If the thread is alive and was created before the event, its process is used, provided that process is in FreeDR's process table. The handle is closed immediately. Nothing is cached and no thread handles are held.
  4. If the header PID disagrees with the resolved thread's process, no actor is assigned.

Unattributed events are still stored with pid NULL. Counters: resolver_attributed_observations, resolver_unattributed_observations, resolver_refreshes (OS checks), resolver_failures, and resolver_failure_thread_query, resolver_failure_process_query, resolver_failure_thread_reused.

Short-lived threads

An event is left unattributed when its thread exited and the thread's start or stop record was lost or is older than the 10 s window.

Noise controls (in pipeline order)

# Filter Dropped Counter
1 Own process Every file event issued by the FreeDR agent process callback_self_filtered
2 Unresolved path Unresolved or ambiguous path, empty, \FI_UNKNOWN terminal_path_discarded
3 Fixed noise paths C:\ProgramData\FreeDR\…, CBS.log, WER temp CSVs, CatRoot2 edbtmp.log, Prefetch\Layout.ini, Windows Update / EdgeUpdate / Edge temp logs, CbsTemp, WinSxS Temp\PendingRenames and InFlight, MRT, Defender definition caches, AppX / SoftwareDistribution / DeliveryOptimization caches, OneDrive logs terminal_noise_discarded
4 Internal I/O FreeDR's own completed I/O under its machine root, when attribution is confirmed. Any uncertain case is kept and counted by reason. internal_io_suppressed, internal_io_retained_*
5 Measured process and path pairs (ADR-0028) wuaucltcore.exe under C:\$WinREAgent; OneDriveSetup.exe, OneDriveStandaloneUpdater.exe, OneDrive.Sync.Service.exe, OneDrive.exe under local AppData Microsoft\OneDrive; MpSigStub.exe on Windows\Temp\<id>\mpengine.dll; TiWorker.exe under Windows\WinSxS. Applied only when the actor is known. terminal_noise_discarded
6 Defender definitions Verified, Microsoft-signed WinDefend reading or opening its own .vdm/.vdf definition files. Everything else from Defender is kept. defender_filtered, defender_*
7 First-only per minute See below repeated_discarded

Per-minute first-only dedupe

Key (pid, event_type, created, lower-case path, lower-case old_path)
Window 60 s from the first kept record, by event time
Rule Keep the first record. Drop any record with the same key within the next 60 s. After that, the next one is kept and starts a new window.
Memory 4,096 keys, oldest evicted first. A burst with more than 4,096 distinct keys can let repeats through. The state is in memory and resets when the ETW session restarts.
Effect One stored row stands for up to a minute of identical activity. The row stores no repeat count.

The USN source uses the same first-only filter.

Known gaps

Gap
Rename target file.rename stores no new name (old_path is always NULL)
File identity volume_serial and file_id are always NULL. Use USN or Artifacts for file IDs.
Reads, opens of existing files, failed operations Not collected
Repeats Hidden for 60 s per key
Own process All FreeDR agent file I/O is dropped
Measured exclusions Remove some real create and write evidence by design (ADR-0028)

Artifact triggers

file.create_open, file.write, file.rename and file.set_info rows queue the path for artifact acquisition. A file.write to an already-inventoried path triggers a new collection.

Health counters

Main groups: callback_*, terminal_path_discarded, terminal_noise_discarded, repeated_discarded, decode_failures, mapping_failures, validation_failures, correlation_* (for example correlation_failed_requests, correlation_outcome_unknown_requests, correlation_unresolved_paths, correlation_actor_missing), internal_io_*, retention_*, resolver_*, defender_*, plus shared ETW ring, loss and TDH counters. See Storage & health.

Verification status

ADR-0055, ADR-0072 and ADR-0077 list native Windows qualification as pending.