]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/secd-154-engine-backoff.m
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / sec / securityd / Regressions / secd-154-engine-backoff.m
1 /*
2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <utilities/SecCFWrappers.h>
26
27 #include "secd_regressions.h"
28 #include "SOSTestDataSource.h"
29
30 #include "SOSRegressionUtilities.h"
31
32 static int kTestTestCount = 10;
33 static int MAX_PENALTY_TIME = 32;
34
35 struct monitor_traffic {
36 CFStringRef key;
37 int penalty_box;
38 int total_consecutive_attempts;
39 int last_write_timestamp;
40 };
41
42 static void clear_penalty(struct monitor_traffic *monitor){
43 monitor->penalty_box = 0;
44 monitor->total_consecutive_attempts = 0;
45 monitor->last_write_timestamp = 0;
46 }
47 static int increase_penalty(int time){
48 if(time == 32)
49 return time;
50 else if(time == 0)
51 return 1;
52 else
53 return (time * 2);
54 }
55
56 static int decrease_penalty(int time){
57 if(time == 0)
58 return time;
59 else if(time == 1)
60 return 0;
61 else
62 return (time/2);
63 }
64
65 //calculate new penalty time based off time passed
66 static void calculate_new_penalty(struct monitor_traffic *monitor, int current_time){
67 int difference = current_time - monitor->last_write_timestamp;
68
69 while(difference){
70 if(difference >= monitor->penalty_box * 2){
71 monitor->penalty_box = decrease_penalty(monitor->penalty_box);
72 difference =- monitor->penalty_box *2;
73 }
74 else
75 break;
76 }
77 }
78
79 static void keychain_changed_notification(struct monitor_traffic *monitor){
80 clear_penalty(monitor);
81 }
82
83 static void initialize_monitor(struct monitor_traffic *monitor){
84 monitor->key = CFSTR("ak|alskdfj:a;lskdjf");
85 monitor->penalty_box = 0;
86 monitor->total_consecutive_attempts = 0;
87 monitor->last_write_timestamp = 0;
88 }
89
90 static int backoff_algorithm(CFArrayRef timestamps, struct monitor_traffic *monitor)
91 {
92 __block int successful_writes = 0;
93 CFNumberRef timestamp;
94
95 CFArrayForEachC(timestamps, timestamp) {
96 int current_time;
97 if(!CFNumberGetValue(timestamp, kCFNumberSInt32Type, &current_time))
98 return successful_writes;
99
100 if(monitor->last_write_timestamp == 0){ //successful default case, initially sending to another peer
101 successful_writes++;
102 }
103 else if(current_time == 0){ //keychain changed notification fired
104 keychain_changed_notification(monitor);
105
106 }
107 else{
108 if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts >= 4){
109 monitor->penalty_box= increase_penalty(monitor->penalty_box);
110 monitor->total_consecutive_attempts++;
111 }
112 else if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts < 4 ){
113 monitor->total_consecutive_attempts++;
114 if(monitor->penalty_box == 0)
115 successful_writes++;
116 }
117 else if((current_time - monitor->last_write_timestamp) >= (2*monitor->penalty_box)){ //we haven't written consecutively for 2* the penalty time
118 monitor->total_consecutive_attempts = 0;
119 calculate_new_penalty(monitor, current_time);
120 successful_writes++;
121 }
122 else if((current_time - monitor->last_write_timestamp) <= (2*monitor->penalty_box)){ //nonconsecutive write came in within the penalty time
123 monitor->penalty_box= increase_penalty(monitor->penalty_box);
124 if(monitor->last_write_timestamp != (current_time-1))
125 monitor->total_consecutive_attempts = 0;
126 else
127 monitor->total_consecutive_attempts++;
128 }
129 }
130 if(current_time != 0)
131 monitor->last_write_timestamp = current_time;
132 }
133
134 return successful_writes;
135 }
136
137 static void tests(void)
138 {
139 struct monitor_traffic *monitor = (struct monitor_traffic*)malloc(sizeof(struct monitor_traffic));
140 initialize_monitor(monitor);
141 CFMutableArrayRef write_attempts = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
142 CFNumberRef timestamp = NULL;
143 int time;
144
145 /*
146 * first test: peer continuously writes for 12 minutes
147 */
148 for(int i = 1; i< 13; i++){
149 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
150 CFArrayAppendValue(write_attempts, timestamp);
151 CFReleaseNull(timestamp);
152 }
153 int successful_writes = backoff_algorithm(write_attempts, monitor);
154 ok(successful_writes == 5, "successfull writes should have only reached 5 minutes");
155 ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should have maxed out to 32 minutes");
156
157 //reset monitor
158 initialize_monitor(monitor);
159 CFArrayRemoveAllValues(write_attempts);
160
161 /*
162 * first test: peer continuously writes for 12 minutes, then backs off 2*(max penalty timeout)
163 */
164 for(int i = 1; i< 13; i++){
165 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
166 CFArrayAppendValue(write_attempts, timestamp);
167 CFReleaseNull(timestamp);
168 }
169 time = 77;
170 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
171 CFArrayAppendValue(write_attempts, timestamp);
172 time = 109;
173 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
174 CFArrayAppendValue(write_attempts, timestamp);
175 successful_writes = backoff_algorithm(write_attempts, monitor);
176 ok(successful_writes == 7, "successfull writes should have only reached 6"); //5 initial writes, then 1 write after enough time passes
177 ok(monitor->penalty_box == (MAX_PENALTY_TIME/4), "penalty box should have maxed out to 16 minutes");
178
179 //reset
180 initialize_monitor(monitor);
181 CFArrayRemoveAllValues(write_attempts);
182
183 /*
184 * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets
185 */
186
187 for(int i = 1; i< 13; i++){
188 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
189 CFArrayAppendValue(write_attempts, timestamp);
190 CFReleaseNull(timestamp);
191 }
192 time = 76; //+ 32*2
193 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
194 CFArrayAppendValue(write_attempts, timestamp);
195 time = 108; //+ 16*2
196 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
197 CFArrayAppendValue(write_attempts, timestamp);
198 time = 124; //+ 8*2
199 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
200 CFArrayAppendValue(write_attempts, timestamp);
201 time = 132; //+ 4*2
202 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
203 CFArrayAppendValue(write_attempts, timestamp);
204 time = 136; //+ 2*2
205 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
206 CFArrayAppendValue(write_attempts, timestamp);
207 time = 138; //+ 1*2
208 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
209 CFArrayAppendValue(write_attempts, timestamp);
210
211 successful_writes = backoff_algorithm(write_attempts, monitor);
212 ok(successful_writes == 11, "successfull writes should have only reached 11");
213 ok(monitor->penalty_box == 0, "penalty box should reset back to 0");
214
215 //reset
216 initialize_monitor(monitor);
217 CFArrayRemoveAllValues(write_attempts);
218
219 /*
220 * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets
221 */
222
223 for(int i = 1; i< 13; i++){
224 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
225 CFArrayAppendValue(write_attempts, timestamp);
226 CFReleaseNull(timestamp);
227 }
228 time = 0; //flag that keychain changed notification fired
229 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
230 CFArrayAppendValue(write_attempts, timestamp);
231
232 for(int i = 1; i< 13; i++){
233 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
234 CFArrayAppendValue(write_attempts, timestamp);
235 CFReleaseNull(timestamp);
236 }
237
238 successful_writes = backoff_algorithm(write_attempts, monitor);
239 ok(successful_writes == 10, "successfull writes should have only reached 10");
240 ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should reset back to 0");
241
242 //reset
243 initialize_monitor(monitor);
244 CFArrayRemoveAllValues(write_attempts);
245
246 /*
247 * first test: peer continuously writes for 5 minutes, then attempts to write again for another 5 minutes, the once much later
248 */
249 for(int i = 1; i< 6; i++){
250 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
251 CFArrayAppendValue(write_attempts, timestamp);
252 CFReleaseNull(timestamp);
253 }
254 time = 40;
255 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
256 CFArrayAppendValue(write_attempts, timestamp);
257
258 for(int i = 100; i< 106; i++){
259 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
260 CFArrayAppendValue(write_attempts, timestamp);
261 CFReleaseNull(timestamp);
262 }
263 time = 250;
264 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
265 CFArrayAppendValue(write_attempts, timestamp);
266
267 successful_writes = backoff_algorithm(write_attempts, monitor);
268 ok(successful_writes == 12, "successfull writes should have only reached 10");
269 ok(monitor->penalty_box == 0, "penalty box should reset back to 0");
270 }
271
272 int secd_154_engine_backoff(int argc, char *const *argv)
273 {
274 plan_tests(kTestTestCount);
275
276 tests();
277
278 return 0;
279 }