xref: /illumos-gate/usr/src/test/os-tests/tests/ksid/ksid.c (revision b210e77709da8e42dfe621e10ccf4be504206058)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
14  */
15 
16 /*
17  * Test the kernel ksid interfaces used by ZFS and SMB
18  */
19 
20 #include <sys/sid.h>
21 #include <sys/time.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <strings.h>
25 #include <errno.h>
26 
27 extern int ksl_bin_search_cutoff;
28 
29 #define	MAX_DOMAINS 8
30 #define	DEFAULT_NUMSIDS 128
31 #define	DEFAULT_ITERS 1
32 
33 char ksid_sids[MAX_DOMAINS+2][256];
34 ksid_t *bad_ksids;
35 
36 boolean_t
37 run_test(ksidlist_t *ksl, uint32_t idx, uint32_t numsids,
38     uint32_t iters, boolean_t pid)
39 {
40 	uint64_t savenum = ksl->ksl_nsid;
41 	uint64_t success = 0;
42 	hrtime_t start, end;
43 	uint32_t i, id;
44 	boolean_t expect_success = (idx < numsids);
45 	ksid_t *ks;
46 
47 	ksl->ksl_nsid = numsids;
48 
49 	start = gethrtime();
50 	if (pid) {
51 		/*
52 		 * Only the first savenum entries are sorted,
53 		 * but ksl_sorted is only used when numsids > cutoff.
54 		 * Use ksl_sorted when idx is among them
55 		 */
56 		if (numsids <= ksl_bin_search_cutoff)
57 			id = ksl->ksl_sids[idx].ks_id;
58 		else if (idx >= savenum)
59 			id = bad_ksids[idx - savenum].ks_id;
60 		else
61 			id = ksl->ksl_sorted[idx]->ks_id;
62 
63 		for (i = 0; i < iters; i++) {
64 			success += (ksidlist_has_pid(ksl, id) ==
65 			    expect_success) ? 1 : 0;
66 		}
67 	} else {
68 		if (idx >= savenum)
69 			ks = &bad_ksids[idx - savenum];
70 		else
71 			ks = &ksl->ksl_sids[idx];
72 
73 		for (i = 0; i < iters; i++) {
74 			success += (ksidlist_has_sid(ksl,
75 			    ksid_getdomain(ks), ks->ks_rid) ==
76 			    expect_success) ? 1 : 0;
77 		}
78 	}
79 	end = gethrtime();
80 
81 	if (iters > 1) {
82 		printf("avg time to %s %s in %d sids "
83 		    "over %d iterations: %llu\n",
84 		    (expect_success) ? "find" : "not find",
85 		    (pid) ? "pid" : "sid", numsids, iters,
86 		    (end - start) / iters);
87 	}
88 
89 	ksl->ksl_nsid = savenum;
90 	return (success == iters);
91 }
92 
93 void
94 usage(char *prog)
95 {
96 	fprintf(stderr, "usage: %s [num sids] [num iters]\n", prog);
97 }
98 
99 int
100 main(int argc, char *argv[])
101 {
102 	credsid_t *kcr;
103 	ksidlist_t *ksl;
104 	uint64_t num_failures = 0;
105 	uint32_t i, j, numsids, iters;
106 	boolean_t retry;
107 
108 	if (argc > 1) {
109 		errno = 0;
110 		numsids = strtoul(argv[1], NULL, 0);
111 		if (errno != 0) {
112 			fprintf(stderr, "error decoding numsids (%s): \n",
113 			    argv[1]);
114 			usage(argv[0]);
115 			perror(argv[0]);
116 			return (errno);
117 		}
118 	} else {
119 		numsids = DEFAULT_NUMSIDS;
120 	}
121 
122 	if (argc > 2) {
123 		iters = strtoul(argv[2], NULL, 0);
124 		if (errno != 0) {
125 			fprintf(stderr, "error decoding iters (%s): \n",
126 			    argv[2]);
127 			usage(argv[0]);
128 			perror(argv[0]);
129 			return (errno);
130 		}
131 	} else {
132 		iters = DEFAULT_ITERS;
133 	}
134 
135 	if (numsids < 1 || iters < 1) {
136 		fprintf(stderr, "both numsids and iters "
137 		    "need to be at least 1\n");
138 		usage(argv[0]);
139 		return (2);
140 	}
141 
142 	/* create MAX_DOMAINS random SIDs */
143 	for (i = 0; i < MAX_DOMAINS; i++) {
144 		(void) snprintf(ksid_sids[i], sizeof (ksid_sids[0]),
145 		    "S-1-5-21-%u-%u-%u",
146 		    arc4random(), arc4random(), arc4random());
147 	}
148 
149 	/* create two unique SIDs for negative testing */
150 	for (j = MAX_DOMAINS; j < MAX_DOMAINS+2; j++) {
151 		do {
152 			retry = B_FALSE;
153 			(void) snprintf(ksid_sids[j], sizeof (ksid_sids[0]),
154 			    "S-1-5-21-%u-%u-%u",
155 			    arc4random(), arc4random(), arc4random());
156 			for (i = 0; i < MAX_DOMAINS; i++) {
157 				if (strncmp(ksid_sids[i], ksid_sids[j],
158 				    sizeof (ksid_sids[0])) == 0) {
159 					retry = B_TRUE;
160 					break;
161 				}
162 			}
163 		} while (retry);
164 	}
165 
166 	ksl = calloc(1, KSIDLIST_MEM(numsids));
167 	ksl->ksl_ref = 1;
168 	ksl->ksl_nsid = numsids;
169 	ksl->ksl_neid = 0;
170 
171 	bad_ksids = malloc(sizeof (ksid_t) * numsids);
172 
173 	/* initialize numsids random sids and ids in the sidlist */
174 	for (i = 0; i < numsids; i++) {
175 		uint32_t idx = arc4random_uniform(MAX_DOMAINS);
176 
177 		ksl->ksl_sids[i].ks_id = arc4random();
178 		ksl->ksl_sids[i].ks_rid = arc4random();
179 		ksl->ksl_sids[i].ks_domain = ksid_lookupdomain(ksid_sids[idx]);
180 		ksl->ksl_sids[i].ks_attr = 0;
181 	}
182 
183 	/*
184 	 * create numsids random sids, whose sids and ids aren't in
185 	 * the sidlist for negative testing
186 	 */
187 	for (i = 0; i < numsids; i++) {
188 		bad_ksids[i].ks_attr = 0;
189 		bad_ksids[i].ks_rid = arc4random();
190 		bad_ksids[i].ks_domain =
191 		    ksid_lookupdomain(ksid_sids[MAX_DOMAINS +
192 		    (arc4random() % 2)]);
193 
194 		do {
195 			retry = B_FALSE;
196 			bad_ksids[i].ks_id = arc4random();
197 			for (j = 0; j < numsids; j++) {
198 				if (ksl->ksl_sids[j].ks_id ==
199 				    bad_ksids[i].ks_id) {
200 					retry = B_TRUE;
201 					break;
202 				}
203 			}
204 		} while (retry);
205 	}
206 
207 	kcr = kcrsid_setsidlist(NULL, ksl);
208 
209 	/* run tests */
210 	for (i = 1; i <= numsids; i++) {
211 		uint32_t s_idx = arc4random_uniform(i);
212 		uint32_t f_idx = numsids + i - 1;
213 
214 		if (!run_test(ksl, s_idx, i, iters, B_FALSE)) {
215 			fprintf(stderr, "Sid search failed unexpectedly: "
216 			    "numsids %u\n", i);
217 			fprintf(stderr, "Bad SID: id %u rid %u domain %s\n",
218 			    ksl->ksl_sids[s_idx].ks_id,
219 			    ksl->ksl_sids[s_idx].ks_rid,
220 			    ksid_getdomain(&ksl->ksl_sids[s_idx]));
221 			num_failures++;
222 		}
223 		if (!run_test(ksl, s_idx, i, iters, B_TRUE)) {
224 			fprintf(stderr, "Pid search failed unexpectedly: "
225 			    "numsids %u\n", i);
226 			fprintf(stderr, "Bad PID: id %u rid %u domain %s\n",
227 			    ksl->ksl_sorted[s_idx]->ks_id,
228 			    ksl->ksl_sorted[s_idx]->ks_rid,
229 			    ksid_getdomain(ksl->ksl_sorted[s_idx]));
230 			num_failures++;
231 		}
232 
233 		if (!run_test(ksl, f_idx, i, iters, B_FALSE)) {
234 			fprintf(stderr, "Sid search succeeded unexpectedly: "
235 			    "numsids %u\n", i);
236 			fprintf(stderr, "Bad SID: id %u rid %u domain %s\n",
237 			    ksl->ksl_sids[f_idx].ks_id,
238 			    ksl->ksl_sids[f_idx].ks_rid,
239 			    ksid_getdomain(&ksl->ksl_sids[f_idx]));
240 			num_failures++;
241 		}
242 		if (!run_test(ksl, f_idx, i, iters, B_TRUE)) {
243 			fprintf(stderr, "Pid search succeeded unexpectedly: "
244 			    "numsids %u\n", i);
245 			fprintf(stderr, "Bad PID: id %u rid %u domain %s\n",
246 			    ksl->ksl_sids[f_idx].ks_id,
247 			    ksl->ksl_sids[f_idx].ks_rid,
248 			    ksid_getdomain(&ksl->ksl_sids[f_idx]));
249 			num_failures++;
250 		}
251 	}
252 
253 	for (i = 0; i < numsids - 1; i++) {
254 		if (ksl->ksl_sorted[i]->ks_id > ksl->ksl_sorted[i + 1]->ks_id) {
255 			fprintf(stderr, "PID %u is not sorted correctly: "
256 			    "%u %u\n", i, ksl->ksl_sorted[i]->ks_id,
257 			    ksl->ksl_sorted[i + 1]->ks_id);
258 			num_failures++;
259 		}
260 		if (ksl->ksl_sids[i].ks_rid > ksl->ksl_sids[i + 1].ks_rid) {
261 			fprintf(stderr, "RID %u is not sorted correctly: "
262 			    "%u %u\n", i, ksl->ksl_sids[i].ks_rid,
263 			    ksl->ksl_sids[i + 1].ks_rid);
264 			num_failures++;
265 		} else if (ksl->ksl_sids[i].ks_rid ==
266 		    ksl->ksl_sids[i + 1].ks_rid &&
267 		    strcmp(ksid_getdomain(&ksl->ksl_sids[i]),
268 		    ksid_getdomain(&ksl->ksl_sids[i + 1])) > 0) {
269 			fprintf(stderr, "SID %u is not sorted correctly: "
270 			    "%s %s\n", i, ksl->ksl_sids[i].ks_rid,
271 			    ksl->ksl_sids[i + 1].ks_rid);
272 			num_failures++;
273 		}
274 	}
275 
276 	if (num_failures != 0) {
277 		fprintf(stderr, "%d failures detected; dumping SID table\n",
278 		    num_failures);
279 		for (i = 0; i < numsids; i++) {
280 			fprintf(stderr, "SID %u: %s-%u -> %u\n", i,
281 			    ksid_getdomain(&ksl->ksl_sids[i]),
282 			    ksl->ksl_sids[i].ks_rid,
283 			    ksl->ksl_sids[i].ks_id);
284 		}
285 
286 		for (i = 0; i < numsids; i++) {
287 			fprintf(stderr, "SID %u: %s-%u -> %u\n",
288 			    i + numsids,
289 			    ksid_getdomain(&bad_ksids[i]),
290 			    bad_ksids[i].ks_rid,
291 			    bad_ksids[i].ks_id);
292 		}
293 
294 		for (i = 0; i < numsids; i++) {
295 			fprintf(stderr, "PID %u: %u\n", i,
296 			    ksl->ksl_sorted[i]->ks_id);
297 		}
298 	} else {
299 		printf("all tests completed successfully!\n");
300 	}
301 
302 	kcrsid_rele(kcr);
303 
304 	return (num_failures);
305 }
306