gss: Add threaded testing of GSS-API!

This commit is contained in:
Nicolas Williams
2025-12-21 01:47:12 -06:00
parent 1274238948
commit 6dc1508e8c
2 changed files with 131 additions and 0 deletions

View File

@@ -82,6 +82,8 @@ static int token_split = 0;
static int version_flag = 0;
static int verbose_flag = 0;
static int help_flag = 0;
static int threaded_flag = 0;
static int num_threads = 8;
static int i_channel_bound = 0;
static char *i_channel_bindings = NULL;
static char *a_channel_bindings = NULL;
@@ -932,6 +934,8 @@ static struct getargs args[] = {
{"token-split", 0, arg_integer, &token_split, "bytes", NULL },
{"on-behalf-of", 0, arg_string, &on_behalf_of_string, "principal",
"send authenticator authz-data AD-ON-BEHALF-OF" },
{"threaded", 0, arg_flag, &threaded_flag, "run threaded test", NULL },
{"num-threads", 0, arg_integer, &num_threads, "number of threads for --threaded", NULL },
{"version", 0, arg_flag, &version_flag, "print version", NULL },
{"verbose", 'v', arg_flag, &verbose_flag, "verbose", NULL },
{"help", 0, arg_flag, &help_flag, NULL, NULL }
@@ -945,6 +949,98 @@ usage (int ret)
exit (ret);
}
/*
* Threaded test for exercising concurrent GSS context establishment.
* This helps detect race conditions in context/credential handling.
*/
struct threaded_test_args {
gss_OID mechoid;
gss_OID nameoid;
const char *target;
gss_cred_id_t client_cred;
int thread_num;
int iterations;
int failed;
};
static void *
threaded_test_worker(void *arg)
{
struct threaded_test_args *ta = arg;
gss_ctx_id_t sctx = GSS_C_NO_CONTEXT;
gss_ctx_id_t cctx = GSS_C_NO_CONTEXT;
gss_OID actual_mech = GSS_C_NO_OID;
gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;
OM_uint32 min_stat;
int i;
for (i = 0; i < ta->iterations; i++) {
if (verbose_flag)
printf("thread %d: iteration %d/%d\n",
ta->thread_num, i + 1, ta->iterations);
sctx = GSS_C_NO_CONTEXT;
cctx = GSS_C_NO_CONTEXT;
deleg_cred = GSS_C_NO_CREDENTIAL;
loop(ta->mechoid, ta->nameoid, ta->target, ta->client_cred,
&sctx, &cctx, &actual_mech, &deleg_cred);
gss_delete_sec_context(&min_stat, &cctx, NULL);
gss_delete_sec_context(&min_stat, &sctx, NULL);
gss_release_cred(&min_stat, &deleg_cred);
}
return NULL;
}
static int
run_threaded_test(gss_OID mechoid, gss_OID nameoid, const char *target,
gss_cred_id_t client_cred, int nthreads, int iterations)
{
HEIMDAL_THREAD_ID *threads;
struct threaded_test_args *thread_args;
int i, ret = 0;
if (verbose_flag)
printf("running threaded test: %d threads, %d iterations each\n",
nthreads, iterations);
threads = calloc(nthreads, sizeof(*threads));
thread_args = calloc(nthreads, sizeof(*thread_args));
if (threads == NULL || thread_args == NULL)
errx(1, "out of memory");
for (i = 0; i < nthreads; i++) {
thread_args[i].mechoid = mechoid;
thread_args[i].nameoid = nameoid;
thread_args[i].target = target;
thread_args[i].client_cred = client_cred;
thread_args[i].thread_num = i;
thread_args[i].iterations = iterations;
thread_args[i].failed = 0;
if (HEIMDAL_THREAD_create(&threads[i], threaded_test_worker,
&thread_args[i]) != 0)
errx(1, "HEIMDAL_THREAD_create failed for thread %d", i);
}
for (i = 0; i < nthreads; i++) {
HEIMDAL_THREAD_join(threads[i], NULL);
if (thread_args[i].failed)
ret = 1;
}
free(threads);
free(thread_args);
if (verbose_flag)
printf("threaded test %s\n", ret ? "FAILED" : "completed");
return ret;
}
int
main(int argc, char **argv)
{
@@ -1177,6 +1273,21 @@ main(int argc, char **argv)
gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
}
if (threaded_flag) {
int iterations = max_loops > 0 ? max_loops : 10;
int ret;
ret = run_threaded_test(mechoid, nameoid, argv[0], client_cred,
num_threads, iterations);
gss_release_cred(&min_stat, &client_cred);
gss_release_oid_set(&min_stat, &actual_mechs);
if (mechoids != GSS_C_NO_OID_SET && mechoids != &mechoid_descs)
gss_release_oid_set(&min_stat, &mechoids);
empty_release();
krb5_free_context(context);
return ret;
}
loop(mechoid, nameoid, argv[0], client_cred,
&sctx, &cctx, &actual_mech, &deleg_cred);

View File

@@ -607,6 +607,26 @@ ${context} \
host/long.test.h5l.se || \
{ eval "$testfailed"; }
test_section "threaded context establishment"
test_section "Getting client initial tickets for threaded test"
test_run ${kinit} --password-file=${objdir}/foopassword user1@${R}
test_section "threaded gss context (krb5)"
test_run ${context} \
--mech-type=krb5 \
--threaded \
--num-threads=4 \
--max-loops=5 \
--name-type=hostbased-service host@lucid.test.h5l.se
test_section "threaded gss context (spnego)"
test_run ${context} \
--mech-type=spnego \
--threaded \
--num-threads=4 \
--max-loops=5 \
--name-type=hostbased-service host@lucid.test.h5l.se
trap "" EXIT
echo "killing kdc (${kdcpid})"