]>
Commit | Line | Data |
---|---|---|
1 | Index: lib/setup.c | |
2 | =================================================================== | |
3 | --- lib/setup.c (revision 29) | |
4 | +++ lib/setup.c (revision 32) | |
5 | @@ -396,7 +396,7 @@ static int __crypt_remove_device(int arg | |
6 | return -EBUSY; | |
7 | } | |
8 | ||
9 | - return backend->remove(options); | |
10 | + return backend->remove(0, options); | |
11 | } | |
12 | ||
13 | static int __crypt_luks_format(int arg, struct setup_backend *backend, struct crypt_options *options) | |
14 | @@ -705,7 +705,10 @@ static int crypt_job(int (*job)(int arg, | |
15 | ||
16 | backend = get_setup_backend(default_backend); | |
17 | ||
18 | - setup_enter(backend,options->icb->log); | |
19 | + if (setup_enter(backend,options->icb->log) < 0) { | |
20 | + r = -ENOSYS; | |
21 | + goto out; | |
22 | + } | |
23 | ||
24 | if (!backend) { | |
25 | set_error("No setup backend available"); | |
26 | Index: lib/internal.h | |
27 | =================================================================== | |
28 | --- lib/internal.h (revision 29) | |
29 | +++ lib/internal.h (revision 32) | |
30 | @@ -40,7 +40,7 @@ struct setup_backend { | |
31 | const char *key); | |
32 | int (*status)(int details, struct crypt_options *options, | |
33 | char **key); | |
34 | - int (*remove)(struct crypt_options *options); | |
35 | + int (*remove)(int force, struct crypt_options *options); | |
36 | ||
37 | const char * (*dir)(void); | |
38 | }; | |
39 | Index: lib/libdevmapper.c | |
40 | =================================================================== | |
41 | --- lib/libdevmapper.c (revision 29) | |
42 | +++ lib/libdevmapper.c (revision 32) | |
43 | @@ -17,13 +17,7 @@ | |
44 | #define DEVICE_DIR "/dev" | |
45 | ||
46 | #define CRYPT_TARGET "crypt" | |
47 | - | |
48 | -#define UDEVSETTLE "/sbin/udevsettle" | |
49 | - | |
50 | -static void run_udevsettle(void) | |
51 | -{ | |
52 | - system(UDEVSETTLE); | |
53 | -} | |
54 | +#define RETRY_COUNT 5 | |
55 | ||
56 | static void set_dm_error(int level, const char *file, int line, | |
57 | const char *f, ...) | |
58 | @@ -38,9 +32,16 @@ static void set_dm_error(int level, cons | |
59 | va_end(va); | |
60 | } | |
61 | ||
62 | +static int _dm_simple(int task, const char *name); | |
63 | + | |
64 | static int dm_init(void) | |
65 | { | |
66 | dm_log_init(set_dm_error); | |
67 | + if (!_dm_simple(DM_DEVICE_LIST_VERSIONS, "test")) { | |
68 | + set_error("Cannot communicate with device-mapper. Is the dm_mod module loaded?"); | |
69 | + return -1; | |
70 | + } | |
71 | + | |
72 | return 1; /* unsafe memory */ | |
73 | } | |
74 | ||
75 | @@ -50,16 +51,6 @@ static void dm_exit(void) | |
76 | dm_lib_release(); | |
77 | } | |
78 | ||
79 | -static void flush_dm_workqueue(void) | |
80 | -{ | |
81 | - /* | |
82 | - * Unfortunately this is the only way to trigger libdevmapper's | |
83 | - * update_nodes function | |
84 | - */ | |
85 | - dm_exit(); | |
86 | - dm_init(); | |
87 | -} | |
88 | - | |
89 | static char *__lookup_dev(char *path, dev_t dev) | |
90 | { | |
91 | struct dirent *entry; | |
92 | @@ -152,6 +143,89 @@ out: | |
93 | return params; | |
94 | } | |
95 | ||
96 | +/* DM helpers */ | |
97 | +static int _dm_simple(int task, const char *name) | |
98 | +{ | |
99 | + int r = 0; | |
100 | + struct dm_task *dmt; | |
101 | + | |
102 | + if (!(dmt = dm_task_create(task))) | |
103 | + return 0; | |
104 | + | |
105 | + if (!dm_task_set_name(dmt, name)) | |
106 | + goto out; | |
107 | + | |
108 | + r = dm_task_run(dmt); | |
109 | + | |
110 | + out: | |
111 | + dm_task_destroy(dmt); | |
112 | + return r; | |
113 | +} | |
114 | + | |
115 | +static int _error_device(struct crypt_options *options) | |
116 | +{ | |
117 | + struct dm_task *dmt; | |
118 | + int r = 0; | |
119 | + | |
120 | + if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) | |
121 | + return 0; | |
122 | + | |
123 | + if (!dm_task_set_name(dmt, options->name)) | |
124 | + goto error; | |
125 | + | |
126 | + if (!dm_task_add_target(dmt, UINT64_C(0), options->size, "error", "")) | |
127 | + goto error; | |
128 | + | |
129 | + if (!dm_task_set_ro(dmt)) | |
130 | + goto error; | |
131 | + | |
132 | + if (!dm_task_no_open_count(dmt)) | |
133 | + goto error; | |
134 | + | |
135 | + if (!dm_task_run(dmt)) | |
136 | + goto error; | |
137 | + | |
138 | + if (!_dm_simple(DM_DEVICE_RESUME, options->name)) { | |
139 | + _dm_simple(DM_DEVICE_CLEAR, options->name); | |
140 | + goto error; | |
141 | + } | |
142 | + | |
143 | + r = 1; | |
144 | + | |
145 | +error: | |
146 | + dm_task_destroy(dmt); | |
147 | + return r; | |
148 | +} | |
149 | + | |
150 | +static int _dm_remove(struct crypt_options *options, int force) | |
151 | +{ | |
152 | + int r = -EINVAL; | |
153 | + int retries = force ? RETRY_COUNT : 1; | |
154 | + | |
155 | + /* If force flag is set, replace device with error, read-only target. | |
156 | + * it should stop processes from reading it and also removed underlying | |
157 | + * device from mapping, so it is usable again. | |
158 | + * Force flag should be used only for temporary devices, which are | |
159 | + * intended to work inside cryptsetup only! | |
160 | + * Anyway, if some process try to read temporary cryptsetup device, | |
161 | + * it is bug - no other process should try touch it (e.g. udev). | |
162 | + */ | |
163 | + if (force) { | |
164 | + _error_device(options); | |
165 | + retries = RETRY_COUNT; | |
166 | + } | |
167 | + | |
168 | + do { | |
169 | + r = _dm_simple(DM_DEVICE_REMOVE, options->name) ? 0 : -EINVAL; | |
170 | + if (--retries) | |
171 | + sleep(1); | |
172 | + } while (r == -EINVAL && retries); | |
173 | + | |
174 | + dm_task_update_nodes(); | |
175 | + | |
176 | + return r; | |
177 | +} | |
178 | + | |
179 | static int dm_create_device(int reload, struct crypt_options *options, | |
180 | const char *key) | |
181 | { | |
182 | @@ -191,24 +265,14 @@ static int dm_create_device(int reload, | |
183 | if (dmi.read_only) | |
184 | options->flags |= CRYPT_FLAG_READONLY; | |
185 | ||
186 | - /* run udevsettle to avoid a race in libdevmapper causing busy dm devices */ | |
187 | - run_udevsettle(); | |
188 | - | |
189 | r = 0; | |
190 | - | |
191 | out: | |
192 | if (r < 0 && !reload) { | |
193 | char *error = (char *)get_error(); | |
194 | if (error) | |
195 | error = strdup(error); | |
196 | - if (dmt) | |
197 | - dm_task_destroy(dmt); | |
198 | ||
199 | - if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) | |
200 | - goto out_restore_error; | |
201 | - if (!dm_task_set_name(dmt, options->name)) | |
202 | - goto out_restore_error; | |
203 | - if (!dm_task_run(dmt)) | |
204 | + if (!_dm_remove(options, 0)) | |
205 | goto out_restore_error; | |
206 | ||
207 | out_restore_error: | |
208 | @@ -224,7 +288,7 @@ out_no_removal: | |
209 | dm_task_destroy(dmt); | |
210 | if(dmt_query) | |
211 | dm_task_destroy(dmt_query); | |
212 | - flush_dm_workqueue(); | |
213 | + dm_task_update_nodes(); | |
214 | return r; | |
215 | } | |
216 | ||
217 | @@ -352,25 +416,12 @@ out: | |
218 | return r; | |
219 | } | |
220 | ||
221 | -static int dm_remove_device(struct crypt_options *options) | |
222 | +static int dm_remove_device(int force, struct crypt_options *options) | |
223 | { | |
224 | - struct dm_task *dmt; | |
225 | - int r = -EINVAL; | |
226 | - | |
227 | - if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) | |
228 | - goto out; | |
229 | - if (!dm_task_set_name(dmt, options->name)) | |
230 | - goto out; | |
231 | - if (!dm_task_run(dmt)) | |
232 | - goto out; | |
233 | - | |
234 | - r = 0; | |
235 | + if (!options || !options->name) | |
236 | + return -EINVAL; | |
237 | ||
238 | -out: | |
239 | - if (dmt) | |
240 | - dm_task_destroy(dmt); | |
241 | - flush_dm_workqueue(); | |
242 | - return r; | |
243 | + return _dm_remove(options, force);; | |
244 | } | |
245 | ||
246 | ||
247 | Index: luks/keyencryption.c | |
248 | =================================================================== | |
249 | --- luks/keyencryption.c (revision 29) | |
250 | +++ luks/keyencryption.c (revision 32) | |
251 | @@ -45,6 +45,11 @@ static inline int round_up_modulo(int x, | |
252 | return div_round_up(x, m) * m; | |
253 | } | |
254 | ||
255 | +static struct setup_backend *cleaner_backend=NULL; | |
256 | +static const char *cleaner_name=NULL; | |
257 | +static uint64_t cleaner_size = 0; | |
258 | +static int devfd=-1; | |
259 | + | |
260 | static int setup_mapping(const char *cipher, const char *name, | |
261 | const char *device, unsigned int payloadOffset, | |
262 | const char *key, size_t keyLength, | |
263 | @@ -52,7 +57,7 @@ static int setup_mapping(const char *cip | |
264 | struct setup_backend *backend, | |
265 | int mode) | |
266 | { | |
267 | - struct crypt_options k; | |
268 | + struct crypt_options k = {0}; | |
269 | struct crypt_options *options = &k; | |
270 | int device_sector_size = sector_size_for_device(device); | |
271 | int r; | |
272 | @@ -66,6 +71,7 @@ static int setup_mapping(const char *cip | |
273 | return -EINVAL; | |
274 | } | |
275 | options->size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE; | |
276 | + cleaner_size = options->size; | |
277 | ||
278 | options->offset = sector; | |
279 | options->cipher = cipher; | |
280 | @@ -87,24 +93,21 @@ static int setup_mapping(const char *cip | |
281 | return r; | |
282 | } | |
283 | ||
284 | -static int clear_mapping(const char *name, struct setup_backend *backend) | |
285 | +static int clear_mapping(const char *name, uint64_t size, struct setup_backend *backend) | |
286 | { | |
287 | - struct crypt_options options; | |
288 | + struct crypt_options options = {0}; | |
289 | options.name=name; | |
290 | - return backend->remove(&options); | |
291 | + options.size = size; | |
292 | + return backend->remove(1, &options); | |
293 | } | |
294 | ||
295 | -/* I miss closures in C! */ | |
296 | -static struct setup_backend *cleaner_backend=NULL; | |
297 | -static const char *cleaner_name=NULL; | |
298 | -static int devfd=0; | |
299 | - | |
300 | static void sigint_handler(int sig) | |
301 | { | |
302 | - if(devfd) | |
303 | + if(devfd >= 0) | |
304 | close(devfd); | |
305 | + devfd = -1; | |
306 | if(cleaner_backend && cleaner_name) | |
307 | - clear_mapping(cleaner_name, cleaner_backend); | |
308 | + clear_mapping(cleaner_name, cleaner_size, cleaner_backend); | |
309 | signal(SIGINT, SIG_DFL); | |
310 | kill(getpid(), SIGINT); | |
311 | } | |
312 | @@ -160,13 +163,14 @@ static int LUKS_endec_template(char *src | |
313 | r = 0; | |
314 | out3: | |
315 | close(devfd); | |
316 | - devfd = 0; | |
317 | + devfd = -1; | |
318 | out2: | |
319 | - clear_mapping(name,backend); | |
320 | + clear_mapping(cleaner_name, cleaner_size, cleaner_backend); | |
321 | out1: | |
322 | signal(SIGINT, SIG_DFL); | |
323 | cleaner_name = NULL; | |
324 | cleaner_backend = NULL; | |
325 | + cleaner_size = 0; | |
326 | free(dmCipherSpec); | |
327 | free(fullpath); | |
328 | free(name); |