1 #include <unix.h>
2 #include <pkcs11.h>
3 #include <pthread.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 
8 #include "testlib.h"
9 
10 static int create_count;
11 static int destroy_count;
12 static int lock_count;
13 static int unlock_count;
14 static CK_RV threaded_test_result;
15 static pthread_mutex_t condmutex = PTHREAD_MUTEX_INITIALIZER;
16 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
17 
create_mutex(CK_VOID_PTR_PTR mutex)18 CK_RV create_mutex(CK_VOID_PTR_PTR mutex) {
19 	pthread_mutex_t* mut = calloc(sizeof(pthread_mutex_t), 1);
20 	if(pthread_mutex_init(mut, NULL) < 0) {
21 		free(mut);
22 		switch(errno) {
23 			case ENOMEM:
24 				return CKR_HOST_MEMORY;
25 			default:
26 				return CKR_GENERAL_ERROR;
27 		}
28 	}
29 
30 	*mutex = mut;
31 	create_count++;
32 	return CKR_OK;
33 }
34 
destroy_mutex(CK_VOID_PTR mutex)35 CK_RV destroy_mutex(CK_VOID_PTR mutex) {
36 	pthread_mutex_t* mut = mutex;
37 
38 	if(pthread_mutex_destroy(mut) < 0) {
39 		switch(errno) {
40 			case EBUSY:
41 			case EINVAL:
42 				return CKR_MUTEX_BAD;
43 			default:
44 				return CKR_GENERAL_ERROR;
45 		}
46 	}
47 
48 	free(mutex);
49 	destroy_count++;
50 	return CKR_OK;
51 }
52 
lock_mutex(CK_VOID_PTR mutex)53 CK_RV lock_mutex(CK_VOID_PTR mutex) {
54 	pthread_mutex_t* mut = mutex;
55 
56 	if(pthread_mutex_lock(mut) < 0) {
57 		switch(errno) {
58 			case EINVAL:
59 			case EAGAIN:
60 			case EDEADLK:
61 			case EPERM:
62 				return CKR_MUTEX_BAD;
63 			default:
64 				return CKR_GENERAL_ERROR;
65 		}
66 	}
67 
68 	lock_count++;
69 	return CKR_OK;
70 }
71 
unlock_mutex(CK_VOID_PTR mutex)72 CK_RV unlock_mutex(CK_VOID_PTR mutex) {
73 	pthread_mutex_t* mut = mutex;
74 
75 	unlock_count++;
76 	if(pthread_mutex_unlock(mut) < 0) {
77 		switch(errno) {
78 			case EPERM:
79 				return CKR_MUTEX_NOT_LOCKED;
80 			case EINVAL:
81 			case EAGAIN:
82 			case EDEADLK:
83 				return CKR_MUTEX_BAD;
84 			default:
85 				return CKR_GENERAL_ERROR;
86 		}
87 	}
88 
89 	return CKR_OK;
90 }
91 
threaded_test()92 int threaded_test() {
93 	CK_SESSION_HANDLE h;
94 	CK_SLOT_ID slot;
95 	CK_RV ret;
96 
97 	printf("In thread:\n");
98 
99 	if((ret = find_slot(CK_TRUE, &slot)) != TEST_RV_OK) {
100 		check_rv(C_Finalize(NULL_PTR));
101 		return (int) ret;
102 	}
103 
104 	check_rv(C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &h));
105 
106 	pthread_mutex_lock(&condmutex);
107 
108 	printf("signaling main thread...\n");
109 	pthread_cond_signal(&cond);
110 	printf("waiting for main thread now...\n");
111 	pthread_cond_wait(&cond, &condmutex);
112 	printf("main thread done, continuing\n");
113 	check_rv(C_CloseSession(h));
114 
115 	return CKR_OK;
116 }
117 
thread_func(void * v EIDT_UNUSED)118 void* thread_func(void* v EIDT_UNUSED) {
119 	threaded_test_result = threaded_test();
120 
121 	pthread_mutex_unlock(&condmutex);
122 
123 	return NULL;
124 }
125 
TEST_FUNC(threads)126 TEST_FUNC(threads) {
127 	CK_C_INITIALIZE_ARGS args_os = {
128 		.flags = CKF_OS_LOCKING_OK,
129 	};
130 	CK_C_INITIALIZE_ARGS args_man = {
131 		.CreateMutex = create_mutex,
132 		.DestroyMutex = destroy_mutex,
133 		.LockMutex = lock_mutex,
134 		.UnlockMutex = unlock_mutex,
135 	};
136 	pthread_t thread;
137 	CK_SESSION_HANDLE handle;
138 	CK_RV ret;
139 	CK_SLOT_ID slot;
140 	CK_SESSION_INFO slinfo;
141 	CK_TOKEN_INFO tkinfo;
142 
143 	check_rv(C_Initialize(&args_os));
144 	check_rv(C_Finalize(NULL_PTR));
145 
146 	check_rv(C_Initialize(&args_man));
147 
148 	if((ret = find_slot(CK_TRUE, &slot)) != TEST_RV_OK) {
149 		check_rv(C_Finalize(NULL_PTR));
150 		return (int)ret;
151 	}
152 
153 	pthread_mutex_lock(&condmutex);
154 #undef CHECK_RV_DEALLOC
155 #define CHECK_RV_DEALLOC pthread_mutex_unlock(&condmutex)
156 
157 	printf("Spawning a thread:\n");
158 	pthread_create(&thread, NULL, thread_func, NULL);
159 
160 	check_rv(C_OpenSession(slot, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &handle));
161 
162 	printf("Thread running, waiting for it to do stuff now:\n");
163 	pthread_cond_wait(&cond, &condmutex);
164 	printf("Thread signaled us, doing something...\n");
165 	check_rv(C_GetTokenInfo(slot, &tkinfo))
166 	verbose_assert(tkinfo.ulSessionCount == 2);
167 	printf("RW session count: %lu\n", tkinfo.ulRwSessionCount);
168 	printf("Signaling thread again\n");
169 	pthread_cond_signal(&cond);
170 	pthread_mutex_unlock(&condmutex);
171 #undef CHECK_RV_DEALLOC
172 #define CHECK_RV_DEALLOC
173 	pthread_join(thread, NULL);
174 	printf("Thread finished\n");
175 
176 	check_rv(C_GetSessionInfo(handle, &slinfo));
177 	verbose_assert((slinfo.flags & CKF_RW_SESSION) == 0);
178 
179 	if(threaded_test_result != TEST_RV_OK) {
180 		return (int)threaded_test_result;
181 	}
182 
183 	check_rv(C_Finalize(NULL_PTR));
184 
185 	printf("created: %d, destroyed: %d, locked: %d, unlocked: %d\n", create_count, destroy_count, lock_count, unlock_count);
186 	verbose_assert(create_count != 0 && destroy_count != 0 && lock_count != 0 && unlock_count != 0);
187 	verbose_assert(create_count == destroy_count);
188 	verbose_assert(lock_count == unlock_count);
189 	return TEST_RV_OK;
190 }
191