1 /*
2 * Copyright (C) 2006-2010 Red Hat, Inc.
3 *
4 * Author: Steven Dake <sdake@redhat.com>
5 *
6 * This file is part of libqb.
7 *
8 * libqb is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * libqb is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with libqb. If not, see <http://www.gnu.org/licenses/>.
20 */
21 #include "os_base.h"
22
23 #include <qb/qbhdb.h>
24 #include <qb/qbatomic.h>
25
26 enum QB_HDB_HANDLE_STATE {
27 QB_HDB_HANDLE_STATE_EMPTY,
28 QB_HDB_HANDLE_STATE_PENDINGREMOVAL,
29 QB_HDB_HANDLE_STATE_ACTIVE
30 };
31
32 static void
33 qb_hdb_create_first_run(struct qb_hdb *hdb)
34 {
35 if (hdb->first_run == QB_TRUE) {
36 hdb->first_run = QB_FALSE;
37 qb_atomic_init();
38 hdb->handles = qb_array_create(32, sizeof(struct qb_hdb_handle));
39 }
40 }
41
42 void
43 qb_hdb_create(struct qb_hdb *hdb)
44 {
45 memset(hdb, 0, sizeof(struct qb_hdb));
46 hdb->first_run = QB_TRUE;
47 qb_hdb_create_first_run(hdb);
48 }
49
50 void
51 qb_hdb_destroy(struct qb_hdb *hdb)
52 {
53 qb_array_free(hdb->handles);
54 memset(hdb, 0, sizeof(struct qb_hdb));
55 }
56
57 int32_t
58 qb_hdb_handle_create(struct qb_hdb *hdb, int32_t instance_size,
59 qb_handle_t * handle_id_out)
60 {
61 int32_t handle;
62 int32_t res = 0;
63 int32_t check;
64 int32_t found = QB_FALSE;
65 void *instance;
66 int32_t i;
67 struct qb_hdb_handle *entry = NULL;
68 int32_t handle_count;
69
70 qb_hdb_create_first_run(hdb);
71
72 handle_count = qb_atomic_int_get(&hdb->handle_count);
73 for (handle = 0; handle < handle_count; handle++) {
74 if (qb_array_index(hdb->handles, handle, (void**)&entry) == 0 &&
75 entry->state == QB_HDB_HANDLE_STATE_EMPTY) {
76 found = QB_TRUE;
77 qb_atomic_int_inc(&entry->ref_count);
78 break;
79 }
80 }
81
82 if (found == QB_FALSE) {
83 res = qb_array_grow(hdb->handles, handle_count + 1U);
84 if (res != 0) {
85 return res;
86 }
87 res = qb_array_index(hdb->handles, handle_count,
88 (void **)&entry);
89 if (res != 0) {
90 return res;
91 }
92 /* NB: qb_array_grow above guarantees that handle_count
93 will not overflow INT32_MAX */
94 qb_atomic_int_inc((int32_t *)&hdb->handle_count);
95 }
96
97 instance = malloc(instance_size);
98 if (instance == 0) {
99 return -ENOMEM;
100 }
101
102 /*
103 * Make sure just positive integers are used for the integrity(?)
104 * checks within 2^32 address space, if we miss 200 times in a row
105 * (just 0 is concerned per specification of random), the PRNG may be
106 * broken -> the value is unspecified, subject of stack allocation.
107 */
108 for (i = 0; i < 200; i++) {
|
(1) Event dont_call: |
"random" should not be used for security-related applications, because linear congruential algorithms are too easy to break. |
|
(2) Event remediation: |
Use a compliant random number generator, such as "/dev/random" or "/dev/urandom" on Unix-like systems, and CNG (Cryptography API: Next Generation) on Windows. |
109 check = random();
110
111 if (check > 0) {
112 break; /* covers also check == UINT32_MAX */
113 }
114 }
115
116 memset(instance, 0, instance_size);
117
118 entry->state = QB_HDB_HANDLE_STATE_ACTIVE;
119 entry->instance = instance;
120 entry->ref_count = 1;
121 entry->check = check;
122
123 *handle_id_out = (((uint64_t) (check)) << 32) | handle;
124
125 return res;
126 }
127
128 int32_t
129 qb_hdb_handle_get(struct qb_hdb * hdb, qb_handle_t handle_in, void **instance)
130 {
131 int32_t check = handle_in >> 32;
132 int32_t handle = handle_in & UINT32_MAX;
133 struct qb_hdb_handle *entry;
134 int32_t handle_count;
135
136 qb_hdb_create_first_run(hdb);
137
138 *instance = NULL;
139 handle_count = qb_atomic_int_get(&hdb->handle_count);
140 if (handle >= handle_count) {
141 return (-EBADF);
142 }
143
144 if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
145 entry->state != QB_HDB_HANDLE_STATE_ACTIVE) {
146 return (-EBADF);
147 }
148
149 if (check != (int32_t) UINT32_MAX && check != entry->check) {
150 return (-EBADF);
151 }
152 qb_atomic_int_inc(&entry->ref_count);
153
154 *instance = entry->instance;
155
156 return (0);
157 }
158
159 int32_t
160 qb_hdb_handle_get_always(struct qb_hdb * hdb, qb_handle_t handle_in,
161 void **instance)
162 {
163 return qb_hdb_handle_get(hdb, handle_in, instance);
164 }
165
166 int32_t
167 qb_hdb_handle_put(struct qb_hdb * hdb, qb_handle_t handle_in)
168 {
169 int32_t check = handle_in >> 32;
170 int32_t handle = handle_in & UINT32_MAX;
171 struct qb_hdb_handle *entry;
172 int32_t handle_count;
173
174 qb_hdb_create_first_run(hdb);
175
176 handle_count = qb_atomic_int_get(&hdb->handle_count);
177 if (handle >= handle_count) {
178 return (-EBADF);
179 }
180
181 if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
182 (check != (int32_t) UINT32_MAX && check != entry->check)) {
183 return (-EBADF);
184 }
185
186 if (qb_atomic_int_dec_and_test(&entry->ref_count)) {
187 if (hdb->destructor) {
188 hdb->destructor(entry->instance);
189 }
190 free(entry->instance);
191 memset(entry, 0, sizeof(struct qb_hdb_handle));
192 }
193 return (0);
194 }
195
196 int32_t
197 qb_hdb_handle_destroy(struct qb_hdb * hdb, qb_handle_t handle_in)
198 {
199 int32_t check = handle_in >> 32;
200 int32_t handle = handle_in & UINT32_MAX;
201 int32_t res;
202 struct qb_hdb_handle *entry;
203 int32_t handle_count;
204
205 qb_hdb_create_first_run(hdb);
206
207 handle_count = qb_atomic_int_get(&hdb->handle_count);
208 if (handle >= handle_count) {
209 return (-EBADF);
210 }
211
212 if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
213 (check != (int32_t) UINT32_MAX && check != entry->check)) {
214 return (-EBADF);
215 }
216
217 entry->state = QB_HDB_HANDLE_STATE_PENDINGREMOVAL;
218 res = qb_hdb_handle_put(hdb, handle_in);
219 return (res);
220 }
221
222 int32_t
223 qb_hdb_handle_refcount_get(struct qb_hdb * hdb, qb_handle_t handle_in)
224 {
225 int32_t check = handle_in >> 32;
226 int32_t handle = handle_in & UINT32_MAX;
227 struct qb_hdb_handle *entry;
228 int32_t handle_count;
229 int32_t refcount = 0;
230
231 qb_hdb_create_first_run(hdb);
232
233 handle_count = qb_atomic_int_get(&hdb->handle_count);
234 if (handle >= handle_count) {
235 return (-EBADF);
236 }
237
238 if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 ||
239 (check != (int32_t) UINT32_MAX && check != entry->check)) {
240 return (-EBADF);
241 }
242
243 refcount = qb_atomic_int_get(&entry->ref_count);
244
245 return (refcount);
246 }
247
248 void
249 qb_hdb_iterator_reset(struct qb_hdb *hdb)
250 {
251 hdb->iterator = 0;
252 }
253
254 int32_t
255 qb_hdb_iterator_next(struct qb_hdb *hdb, void **instance, qb_handle_t * handle)
256 {
257 int32_t res = -1;
258 uint64_t checker;
259 struct qb_hdb_handle *entry;
260 uint32_t handle_count;
261
262 handle_count = qb_atomic_int_get(&hdb->handle_count);
263 while (hdb->iterator < handle_count) {
264 res = qb_array_index(hdb->handles,
265 hdb->iterator,
266 (void **)&entry);
267 if (res != 0) {
268 break;
269 }
270 checker = (uint64_t) (entry->check);
271 *handle = (checker << 32) | hdb->iterator;
272 res = qb_hdb_handle_get(hdb, *handle, instance);
273
274 hdb->iterator += 1;
275 if (res == 0) {
276 break;
277 }
278 }
279 return (res);
280 }
281
282 uint32_t
283 qb_hdb_base_convert(qb_handle_t handle)
284 {
285 return (handle & UINT32_MAX);
286 }
287
288 uint64_t
289 qb_hdb_nocheck_convert(uint32_t handle)
290 {
291 uint64_t retvalue = ((uint64_t) UINT32_MAX) << 32 | handle;
292
293 return (retvalue);
294 }
295