1 /*
2  * PROJECT:     ReactOS kernel-mode tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Kernel mode tests for process quotas
5  * COPYRIGHT:   Copyright 2021 George Bișoc <george.bisoc@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 START_TEST(PsQuota)
11 {
12     NTSTATUS Status;
13     VM_COUNTERS VmCounters;
14     QUOTA_LIMITS QuotaLimits;
15     SIZE_T NonPagedUsage, PagedUsage;
16     PEPROCESS Process = PsGetCurrentProcess();
17 
18     /* Guard the quota operations in a guarded region */
19     KeEnterGuardedRegion();
20 
21     /* Report the current process' quota limits */
22     Status = ZwQueryInformationProcess(NtCurrentProcess(),
23                                        ProcessQuotaLimits,
24                                        &QuotaLimits,
25                                        sizeof(QuotaLimits),
26                                        NULL);
27     if (skip(NT_SUCCESS(Status), "Failed to query quota limits -- %lx\n", Status))
28     {
29         return;
30     }
31 
32     trace("Process paged pool quota limit -- %lu\n", QuotaLimits.PagedPoolLimit);
33     trace("Process non paged pool quota limit -- %lu\n", QuotaLimits.NonPagedPoolLimit);
34     trace("Process page file quota limit -- %lu\n\n", QuotaLimits.PagefileLimit);
35 
36     /* Query the quota usage */
37     Status = ZwQueryInformationProcess(NtCurrentProcess(),
38                                        ProcessVmCounters,
39                                        &VmCounters,
40                                        sizeof(VmCounters),
41                                        NULL);
42     if (skip(NT_SUCCESS(Status), "Failed to query quota usage -- %lx\n", Status))
43     {
44         return;
45     }
46 
47     /* Test that quotas usage are within limits */
48     ok(VmCounters.QuotaNonPagedPoolUsage < QuotaLimits.NonPagedPoolLimit, "Non paged quota over limits (usage -> %lu || limit -> %lu)\n",
49        VmCounters.QuotaNonPagedPoolUsage, QuotaLimits.NonPagedPoolLimit);
50     ok(VmCounters.QuotaPagedPoolUsage < QuotaLimits.PagedPoolLimit, "Paged quota over limits (usage -> %lu || limit -> %lu)\n",
51        VmCounters.QuotaPagedPoolUsage, QuotaLimits.PagedPoolLimit);
52 
53     /* Cache the quota usage pools for later checks  */
54     NonPagedUsage = VmCounters.QuotaNonPagedPoolUsage;
55     PagedUsage = VmCounters.QuotaPagedPoolUsage;
56 
57     /* Charge some paged and non paged quotas */
58     Status = PsChargeProcessNonPagedPoolQuota(Process, 0x200);
59     ok_irql(PASSIVE_LEVEL);
60     ok_eq_hex(Status, STATUS_SUCCESS);
61 
62     Status = PsChargeProcessPagedPoolQuota(Process, 0x500);
63     ok_irql(PASSIVE_LEVEL);
64     ok_eq_hex(Status, STATUS_SUCCESS);
65 
66     /* Query the quota usage again */
67     Status = ZwQueryInformationProcess(NtCurrentProcess(),
68                                        ProcessVmCounters,
69                                        &VmCounters,
70                                        sizeof(VmCounters),
71                                        NULL);
72     if (skip(NT_SUCCESS(Status), "Failed to query quota usage -- %lx\n", Status))
73     {
74         return;
75     }
76 
77 
78     /* Test again the usage that's within limits */
79     ok(VmCounters.QuotaNonPagedPoolUsage < QuotaLimits.NonPagedPoolLimit, "Non paged quota over limits (usage -> %lu || limit -> %lu)\n",
80        VmCounters.QuotaNonPagedPoolUsage, QuotaLimits.NonPagedPoolLimit);
81     ok(VmCounters.QuotaPagedPoolUsage < QuotaLimits.PagedPoolLimit, "Paged quota over limits (usage -> %lu || limit -> %lu)\n",
82        VmCounters.QuotaPagedPoolUsage, QuotaLimits.PagedPoolLimit);
83 
84     /*
85      * Make sure the results are consistent, that nobody else
86      * is charging quotas other than us.
87      */
88     ok_eq_size(VmCounters.QuotaNonPagedPoolUsage, NonPagedUsage + 0x200);
89     ok_eq_size(VmCounters.QuotaPagedPoolUsage, PagedUsage + 0x500);
90 
91     /* Report the quota usage */
92     trace("=== QUOTA USAGE AFTER CHARGE ===\n\n");
93     trace("Process paged pool quota usage -- %lu\n", VmCounters.QuotaPagedPoolUsage);
94     trace("Process paged pool quota peak -- %lu\n", VmCounters.QuotaPeakPagedPoolUsage);
95     trace("Process non paged pool quota usage -- %lu\n", VmCounters.QuotaNonPagedPoolUsage);
96     trace("Process non paged pool quota peak -- %lu\n", VmCounters.QuotaPeakNonPagedPoolUsage);
97     trace("Process page file quota usage -- %lu\n", VmCounters.PagefileUsage);
98     trace("Process page file quota peak -- %lu\n\n", VmCounters.PeakPagefileUsage);
99 
100     /* Return the quotas we've charged up */
101     PsReturnProcessNonPagedPoolQuota(Process, 0x200);
102     PsReturnProcessPagedPoolQuota(Process, 0x500);
103 
104     /* Query the quota usage again */
105     Status = ZwQueryInformationProcess(NtCurrentProcess(),
106                                        ProcessVmCounters,
107                                        &VmCounters,
108                                        sizeof(VmCounters),
109                                        NULL);
110     if (skip(NT_SUCCESS(Status), "Failed to query quota usage -- %lx\n", Status))
111     {
112         return;
113     }
114 
115     /*
116      * Check that nobody else has returned quotas
117      * but only us.
118      */
119     ok_eq_size(VmCounters.QuotaNonPagedPoolUsage, NonPagedUsage);
120     ok_eq_size(VmCounters.QuotaPagedPoolUsage, PagedUsage);
121 
122     /* Report the usage again */
123     trace("=== QUOTA USAGE AFTER RETURN ===\n\n");
124     trace("Process paged pool quota usage -- %lu\n", VmCounters.QuotaPagedPoolUsage);
125     trace("Process paged pool quota peak -- %lu\n", VmCounters.QuotaPeakPagedPoolUsage);
126     trace("Process non paged pool quota usage -- %lu\n", VmCounters.QuotaNonPagedPoolUsage);
127     trace("Process non paged pool quota peak -- %lu\n", VmCounters.QuotaPeakNonPagedPoolUsage);
128     trace("Process page file quota usage -- %lu\n", VmCounters.PagefileUsage);
129     trace("Process page file quota peak -- %lu\n\n", VmCounters.PeakPagefileUsage);
130 
131     /* We're done, leave the region */
132     KeLeaveGuardedRegion();
133 }
134