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