summaryrefslogtreecommitdiff
path: root/filesys/miniFilter/NameChanger/nchelper.c
blob: 489c435e3fe062490e30a6d94bf79a4d3862dc51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/*++

Copyright (c) 2008 - 2009  Microsoft Corporation

Module Name:

    nchelper.c

Abstract:

    Contains helper routines of general applicability across name changer.

Environment:

    Kernel mode

--*/

#include "nc.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, NcAllocateEResource)
#pragma alloc_text(PAGE, NcCreateFileHelper)
#pragma alloc_text(PAGE, NcGetFileNameInformation)
#endif

_When_(Data == NULL, _Pre_satisfies_(FileObject != NULL && Instance != NULL))
_When_(FileObject == NULL || Instance == NULL, _Pre_satisfies_(Data != NULL))
NTSTATUS
NcGetFileNameInformation(
    _In_opt_ PFLT_CALLBACK_DATA Data,
    _In_opt_ PFILE_OBJECT FileObject,
    _In_opt_ PFLT_INSTANCE Instance,
    _In_ FLT_FILE_NAME_OPTIONS NameOptions,
    _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation
    )
/*++

Routine Description:

    This function is a wrapper to call the correct variant of
    FltGetFileNameInformation depending on the information we happen to
    have available.

Arguments:

    Data - Pointer to the callback data structure associated with a request.
        This is optional, but if not specified, FileObject and Instance must
        be supplied.

    FileObject - Pointer to the file object to query a name on.  Optional,
        but if not supplied, Data must be supplied.

    Instance - Pointer to the instance of our filter to query the name on.
        Optional, but if not supplied, Data must be supplied.

    NameOptions - FLT_FILE_NAME_* flags for this request.

    FileNameInformation - On output, contains the file name information
        resulting from this query.  On failure, contents are undefined.
        On success, caller is responsible for releasing this with
        FltReleaseFileNameInformation.

Return Value:

    Returns the status of the operation.

--*/
{
    NTSTATUS Status;

    PAGED_CODE();

    FLT_ASSERT( Data || FileObject );

    *FileNameInformation = NULL;

    if (ARGUMENT_PRESENT( Data )) {

        Status = FltGetFileNameInformation( Data,
                                            NameOptions,
                                            FileNameInformation );

    } else if (ARGUMENT_PRESENT( FileObject )) {

        Status = FltGetFileNameInformationUnsafe( FileObject,
                                                  Instance,
                                                  NameOptions,
                                                  FileNameInformation );
    //
    //  This should never happen, as either Data or FileObject must be non-NULL.
    //

    } else {

        FLT_ASSERT( FALSE );
        Status = STATUS_INVALID_PARAMETER;
    }

    return Status;
}

NTSTATUS
NcAllocateEResource(
    _Out_ PERESOURCE * OutputLock
    )
/*++

Routine Description:

    This function allocates a new ERESOURCE.

Arguments:

    OutputLock - On output, points to a newly allocated ERESOURCE.  This
        value is undefined on failure.  Caller is responsible for deleting
        this with a call to NcFreeEResource.

Return Value:

    Returns the status of the operation.

--*/
{
    NTSTATUS Status;

    PERESOURCE Lock = NULL;
    BOOLEAN DeleteLock = FALSE;

    PAGED_CODE();

    Lock = ExAllocatePoolZero( NonPagedPool,
                               sizeof(ERESOURCE),
                               NC_LOCK_TAG );

    if (Lock == NULL) {

        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto NcAllocateEResourceCleanup;
    }

    Status = ExInitializeResourceLite( Lock );

    if (!NT_SUCCESS( Status )) {

        goto NcAllocateEResourceCleanup;
    }

    Status = STATUS_SUCCESS;
    DeleteLock = TRUE;
    *OutputLock = Lock;

NcAllocateEResourceCleanup:

    if (!NT_SUCCESS( Status )) {

        if (Lock) {

            if (DeleteLock) {

                ExDeleteResourceLite( Lock );
            }
            ExFreePoolWithTag( Lock, NC_LOCK_TAG );
        }
    }
    return Status;
}

VOID
NcFreeEResource(
    _In_ PERESOURCE Lock
    )
/*++

Routine Description:

    This function frees an ERESOURCE.

Arguments:

    Lock - Points to an ERESOURCE allocated previously via
        NcAllocateEResource that needs to be torn down.

Return Value:

    Returns the status of the operation.

--*/
{
    ExDeleteResourceLite( Lock );
    ExFreePoolWithTag( Lock, NC_LOCK_TAG );
}

NTSTATUS
NcCreateFileHelper (
    _In_ PFLT_FILTER Filter,
    _In_opt_ PFLT_INSTANCE Instance,
    _Out_ PHANDLE FileHandle,
    _Outptr_opt_ PFILE_OBJECT *FileObject,
    _In_ ACCESS_MASK DesiredAccess,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _Out_ PIO_STATUS_BLOCK IoStatusBlock,
    _In_opt_ PLARGE_INTEGER AllocationSize,
    _In_ ULONG FileAttributes,
    _In_ ULONG ShareAccess,
    _In_ ULONG CreateDisposition,
    _In_ ULONG CreateOptions,
    _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
    _In_ ULONG EaLength,
    _In_ ULONG Flags,
    _In_opt_ PFILE_OBJECT ParentFileObject
    )
{

#if FLT_MGR_LONGHORN
    IO_DRIVER_CREATE_CONTEXT DriverContext;
#endif
    NTSTATUS Status;

    PAGED_CODE();

#if FLT_MGR_LONGHORN
    IoInitializeDriverCreateContext( &DriverContext );

    if (ARGUMENT_PRESENT( ParentFileObject )) {
        PTXN_PARAMETER_BLOCK TxnInfo;

        TxnInfo = IoGetTransactionParameterBlock( ParentFileObject );

        //
        //  If we have a FileObject, and if it has a transaction, pass the
        //  same transaction context along to our internal creates.
        //
        //  TxfInfo will be valid so long as the file object is valid, which
        //  it is assumed to be across the call to this routine.
        //

        DriverContext.TxnParameters = TxnInfo;
    }
#else
    UNREFERENCED_PARAMETER( ParentFileObject );
#endif

    Status = NcCreateFileEx2( Filter,
                              Instance,
                              FileHandle,
                              FileObject,
                              DesiredAccess,
                              ObjectAttributes,
                              IoStatusBlock,
                              AllocationSize,
                              FileAttributes,
                              ShareAccess,
                              CreateDisposition,
                              CreateOptions,
                              EaBuffer,
                              EaLength,
                              Flags,
#if FLT_MGR_LONGHORN
                              &DriverContext );
#else
                              NULL );
#endif

    return Status;
}


NTSTATUS
NcSetCancelCompletion(
    _In_ PFLT_CALLBACK_DATA Data,
    _In_ PFLT_COMPLETE_CANCELED_CALLBACK CanceledCallback
    )
/*++

Routine Description:

    This sets the cancel routine attached to the request.  We
    synchronize against the request being cancelled via the system
    global cancel spinlock, and if the request is already cancelled,
    this function returns STATUS_CANCELLED to the caller to
    indicate that the caller must clean up the request.  Otherwise,
    the cancel routine is set and immediately upon return any
    cancellation will be via that mechanism.

    NOTE: This routine must be nonpaged, since we require
    synchronization with the system global cancel spinlock.

Arguments:

    Data - Pointer to the request we wish to assign cancellation to.

    CanceledCallback - Pointer to the functin to call upon
                       cancellation.

Return Value:

    STATUS_CANCELLED if the request should be completed by the
    caller, STATUS_SUCCESS to indicate that the cancellation
    routine is associated with the request.

--*/
{
    NTSTATUS Status;
    KIRQL OldIrql;

    IoAcquireCancelSpinLock( &OldIrql );

    if (FltIsIoCanceled( Data )) {
        IoReleaseCancelSpinLock( OldIrql );
        return STATUS_CANCELLED;

    }
    Status = FltSetCancelCompletion( Data, CanceledCallback );

    IoReleaseCancelSpinLock( OldIrql );
    return Status;
}


LONG
NcExceptionFilter (
    _In_ PEXCEPTION_POINTERS ExceptionPointer,
    _In_ BOOLEAN AccessingUserBuffer
    )
/*++

Routine Description:

    Exception filter to catch errors touching user buffers.

Arguments:

    ExceptionPointer - The exception record.

    AccessingUserBuffer - If TRUE, overrides FsRtlIsNtStatusExpected to allow
                          the caller to munge the error to a desired status.

Return Value:

    EXCEPTION_EXECUTE_HANDLER - If the exception handler should be run.

    EXCEPTION_CONTINUE_SEARCH - If a higher exception handler should take care of
                                this exception.

--*/
{
    NTSTATUS Status;

    Status = ExceptionPointer->ExceptionRecord->ExceptionCode;

    //
    //  Certain exceptions shouldn't be dismissed within the namechanger filter
    //  unless we're touching user memory.
    //

    if (!FsRtlIsNtstatusExpected( Status ) &&
        !AccessingUserBuffer) {

        return EXCEPTION_CONTINUE_SEARCH;
    }

    return EXCEPTION_EXECUTE_HANDLER;
}