]> git.saurik.com Git - apple/security.git/blob - keychain/securityd/Regressions/secd-154-engine-backoff.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / 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 #include "SOSAccountTesting.h"
32
33 #if SOS_ENABLED
34
35 static int kTestTestCount = 10;
36 static int MAX_PENALTY_TIME = 32;
37
38 struct monitor_traffic {
39 CFStringRef key;
40 int penalty_box;
41 int total_consecutive_attempts;
42 int last_write_timestamp;
43 };
44
45 static void clear_penalty(struct monitor_traffic *monitor){
46 monitor->penalty_box = 0;
47 monitor->total_consecutive_attempts = 0;
48 monitor->last_write_timestamp = 0;
49 }
50 static int increase_penalty(int time){
51 if(time == 32)
52 return time;
53 else if(time == 0)
54 return 1;
55 else
56 return (time * 2);
57 }
58
59 static int decrease_penalty(int time){
60 if(time == 0)
61 return time;
62 else if(time == 1)
63 return 0;
64 else
65 return (time/2);
66 }
67
68 //calculate new penalty time based off time passed
69 static void calculate_new_penalty(struct monitor_traffic *monitor, int current_time){
70 int difference = current_time - monitor->last_write_timestamp;
71
72 while(difference){
73 if(difference >= monitor->penalty_box * 2){
74 monitor->penalty_box = decrease_penalty(monitor->penalty_box);
75 difference =- monitor->penalty_box *2;
76 }
77 else
78 break;
79 }
80 }
81
82 static void keychain_changed_notification(struct monitor_traffic *monitor){
83 clear_penalty(monitor);
84 }
85
86 static void initialize_monitor(struct monitor_traffic *monitor){
87 monitor->key = CFSTR("ak|alskdfj:a;lskdjf");
88 monitor->penalty_box = 0;
89 monitor->total_consecutive_attempts = 0;
90 monitor->last_write_timestamp = 0;
91 }
92
93 static int backoff_algorithm(CFArrayRef timestamps, struct monitor_traffic *monitor)
94 {
95 __block int successful_writes = 0;
96 CFNumberRef timestamp;
97
98 CFArrayForEachC(timestamps, timestamp) {
99 int current_time;
100 if(!CFNumberGetValue(timestamp, kCFNumberSInt32Type, &current_time))
101 return successful_writes;
102
103 if(monitor->last_write_timestamp == 0){ //successful default case, initially sending to another peer
104 successful_writes++;
105 }
106 else if(current_time == 0){ //keychain changed notification fired
107 keychain_changed_notification(monitor);
108
109 }
110 else{
111 if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts >= 4){
112 monitor->penalty_box= increase_penalty(monitor->penalty_box);
113 monitor->total_consecutive_attempts++;
114 }
115 else if(monitor->last_write_timestamp == (current_time -1) && monitor->total_consecutive_attempts < 4 ){
116 monitor->total_consecutive_attempts++;
117 if(monitor->penalty_box == 0)
118 successful_writes++;
119 }
120 else if((current_time - monitor->last_write_timestamp) >= (2*monitor->penalty_box)){ //we haven't written consecutively for 2* the penalty time
121 monitor->total_consecutive_attempts = 0;
122 calculate_new_penalty(monitor, current_time);
123 successful_writes++;
124 }
125 else if((current_time - monitor->last_write_timestamp) <= (2*monitor->penalty_box)){ //nonconsecutive write came in within the penalty time
126 monitor->penalty_box= increase_penalty(monitor->penalty_box);
127 if(monitor->last_write_timestamp != (current_time-1))
128 monitor->total_consecutive_attempts = 0;
129 else
130 monitor->total_consecutive_attempts++;
131 }
132 }
133 if(current_time != 0)
134 monitor->last_write_timestamp = current_time;
135 }
136
137 return successful_writes;
138 }
139
140 static void tests(void)
141 {
142 struct monitor_traffic *monitor = (struct monitor_traffic*)malloc(sizeof(struct monitor_traffic));
143 initialize_monitor(monitor);
144 CFMutableArrayRef write_attempts = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
145 CFNumberRef timestamp = NULL;
146 int time;
147
148 /*
149 * first test: peer continuously writes for 12 minutes
150 */
151 for(int i = 1; i< 13; i++){
152 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
153 CFArrayAppendValue(write_attempts, timestamp);
154 CFReleaseNull(timestamp);
155 }
156 int successful_writes = backoff_algorithm(write_attempts, monitor);
157 ok(successful_writes == 5, "successfull writes should have only reached 5 minutes");
158 ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should have maxed out to 32 minutes");
159
160 //reset monitor
161 initialize_monitor(monitor);
162 CFArrayRemoveAllValues(write_attempts);
163
164 /*
165 * first test: peer continuously writes for 12 minutes, then backs off 2*(max penalty timeout)
166 */
167 for(int i = 1; i< 13; i++){
168 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
169 CFArrayAppendValue(write_attempts, timestamp);
170 CFReleaseNull(timestamp);
171 }
172 time = 77;
173 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
174 CFArrayAppendValue(write_attempts, timestamp);
175 time = 109;
176 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
177 CFArrayAppendValue(write_attempts, timestamp);
178 successful_writes = backoff_algorithm(write_attempts, monitor);
179 ok(successful_writes == 7, "successfull writes should have only reached 6"); //5 initial writes, then 1 write after enough time passes
180 ok(monitor->penalty_box == (MAX_PENALTY_TIME/4), "penalty box should have maxed out to 16 minutes");
181
182 //reset
183 initialize_monitor(monitor);
184 CFArrayRemoveAllValues(write_attempts);
185
186 /*
187 * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets
188 */
189
190 for(int i = 1; i< 13; i++){
191 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
192 CFArrayAppendValue(write_attempts, timestamp);
193 CFReleaseNull(timestamp);
194 }
195 time = 76; //+ 32*2
196 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
197 CFArrayAppendValue(write_attempts, timestamp);
198 time = 108; //+ 16*2
199 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
200 CFArrayAppendValue(write_attempts, timestamp);
201 time = 124; //+ 8*2
202 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
203 CFArrayAppendValue(write_attempts, timestamp);
204 time = 132; //+ 4*2
205 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
206 CFArrayAppendValue(write_attempts, timestamp);
207 time = 136; //+ 2*2
208 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
209 CFArrayAppendValue(write_attempts, timestamp);
210 time = 138; //+ 1*2
211 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
212 CFArrayAppendValue(write_attempts, timestamp);
213
214 successful_writes = backoff_algorithm(write_attempts, monitor);
215 ok(successful_writes == 11, "successfull writes should have only reached 11");
216 ok(monitor->penalty_box == 0, "penalty box should reset back to 0");
217
218 //reset
219 initialize_monitor(monitor);
220 CFArrayRemoveAllValues(write_attempts);
221
222 /*
223 * first test: peer continuously writes for 12 minutes, then backs off exponentially until everything effectively resets
224 */
225
226 for(int i = 1; i< 13; i++){
227 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
228 CFArrayAppendValue(write_attempts, timestamp);
229 CFReleaseNull(timestamp);
230 }
231 time = 0; //flag that keychain changed notification fired
232 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
233 CFArrayAppendValue(write_attempts, timestamp);
234
235 for(int i = 1; i< 13; i++){
236 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
237 CFArrayAppendValue(write_attempts, timestamp);
238 CFReleaseNull(timestamp);
239 }
240
241 successful_writes = backoff_algorithm(write_attempts, monitor);
242 ok(successful_writes == 10, "successfull writes should have only reached 10");
243 ok(monitor->penalty_box == MAX_PENALTY_TIME, "penalty box should reset back to 0");
244
245 //reset
246 initialize_monitor(monitor);
247 CFArrayRemoveAllValues(write_attempts);
248
249 /*
250 * first test: peer continuously writes for 5 minutes, then attempts to write again for another 5 minutes, the once much later
251 */
252 for(int i = 1; i< 6; i++){
253 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
254 CFArrayAppendValue(write_attempts, timestamp);
255 CFReleaseNull(timestamp);
256 }
257 time = 40;
258 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
259 CFArrayAppendValue(write_attempts, timestamp);
260
261 for(int i = 100; i< 106; i++){
262 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i);
263 CFArrayAppendValue(write_attempts, timestamp);
264 CFReleaseNull(timestamp);
265 }
266 time = 250;
267 timestamp = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &time);
268 CFArrayAppendValue(write_attempts, timestamp);
269
270 successful_writes = backoff_algorithm(write_attempts, monitor);
271 ok(successful_writes == 12, "successfull writes should have only reached 10");
272 ok(monitor->penalty_box == 0, "penalty box should reset back to 0");
273 }
274 #endif
275
276 int secd_154_engine_backoff(int argc, char *const *argv)
277 {
278 #if SOS_ENABLED
279 plan_tests(kTestTestCount);
280 tests();
281 #else
282 plan_tests(0);
283 #endif
284 return 0;
285 }