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