Fix possible leaks in blockwise read/write code.
[platform/upstream/cryptsetup.git] / lib / utils.c
1 /*
2  * utils - miscellaneous device utilities for cryptsetup
3  *
4  * Copyright (C) 2004, Christophe Saout <christophe@saout.de>
5  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
6  * Copyright (C) 2009-2011, Red Hat, Inc. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <errno.h>
28 #include <linux/fs.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/ioctl.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include <sys/resource.h>
37
38 #include "libcryptsetup.h"
39 #include "internal.h"
40
41 static char *error=NULL;
42
43 __attribute__((format(printf, 1, 0)))
44 void set_error_va(const char *fmt, va_list va)
45 {
46         int r;
47
48         if(error) {
49                 free(error);
50                 error = NULL;
51         }
52
53         if(!fmt) return;
54
55         r = vasprintf(&error, fmt, va);
56         if (r < 0) {
57                 free(error);
58                 error = NULL;
59                 return;
60         }
61
62         if (r && error[r - 1] == '\n')
63                 error[r - 1] = '\0';
64 }
65
66 __attribute__((format(printf, 1, 2)))
67 void set_error(const char *fmt, ...)
68 {
69         va_list va;
70
71         va_start(va, fmt);
72         set_error_va(fmt, va);
73         va_end(va);
74 }
75
76 const char *get_error(void)
77 {
78         return error;
79 }
80
81 static int get_alignment(int fd)
82 {
83         int alignment = DEFAULT_MEM_ALIGNMENT;
84
85 #ifdef _PC_REC_XFER_ALIGN
86         alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
87         if (alignment < 0)
88                 alignment = DEFAULT_MEM_ALIGNMENT;
89 #endif
90         return alignment;
91 }
92
93 static void *aligned_malloc(void **base, int size, int alignment)
94 {
95 #ifdef HAVE_POSIX_MEMALIGN
96         return posix_memalign(base, alignment, size) ? NULL : *base;
97 #else
98 /* Credits go to Michal's padlock patches for this alignment code */
99         char *ptr;
100
101         ptr  = malloc(size + alignment);
102         if(ptr == NULL) return NULL;
103
104         *base = ptr;
105         if(alignment > 1 && ((long)ptr & (alignment - 1))) {
106                 ptr += alignment - ((long)(ptr) & (alignment - 1));
107         }
108         return ptr;
109 #endif
110 }
111 static int sector_size(int fd) 
112 {
113         int bsize;
114         if (ioctl(fd,BLKSSZGET, &bsize) < 0)
115                 return -EINVAL;
116         else
117                 return bsize;
118 }
119
120 int sector_size_for_device(const char *device)
121 {
122         int fd = open(device, O_RDONLY);
123         int r;
124         if(fd < 0)
125                 return -EINVAL;
126         r = sector_size(fd);
127         close(fd);
128         return r;
129 }
130
131 ssize_t write_blockwise(int fd, void *orig_buf, size_t count)
132 {
133         void *hangover_buf, *hangover_buf_base = NULL;
134         void *buf, *buf_base = NULL;
135         int r, hangover, solid, bsize, alignment;
136         ssize_t ret = -1;
137
138         if ((bsize = sector_size(fd)) < 0)
139                 return bsize;
140
141         hangover = count % bsize;
142         solid = count - hangover;
143         alignment = get_alignment(fd);
144
145         if ((long)orig_buf & (alignment - 1)) {
146                 buf = aligned_malloc(&buf_base, count, alignment);
147                 if (!buf)
148                         goto out;
149                 memcpy(buf, orig_buf, count);
150         } else
151                 buf = orig_buf;
152
153         r = write(fd, buf, solid);
154         if (r < 0 || r != solid)
155                 goto out;
156
157         if (hangover) {
158                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
159                 if (!hangover_buf)
160                         goto out;
161
162                 r = read(fd, hangover_buf, bsize);
163                 if (r < 0 || r != bsize)
164                         goto out;
165
166                 r = lseek(fd, -bsize, SEEK_CUR);
167                 if (r < 0)
168                         goto out;
169                 memcpy(hangover_buf, (char*)buf + solid, hangover);
170
171                 r = write(fd, hangover_buf, bsize);
172                 if (r < 0 || r != bsize)
173                         goto out;
174         }
175         ret = count;
176 out:
177         free(hangover_buf_base);
178         if (buf != orig_buf)
179                 free(buf_base);
180         return ret;
181 }
182
183 ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
184         void *hangover_buf, *hangover_buf_base = NULL;
185         void *buf, *buf_base = NULL;
186         int r, hangover, solid, bsize, alignment;
187         ssize_t ret = -1;
188
189         if ((bsize = sector_size(fd)) < 0)
190                 return bsize;
191
192         hangover = count % bsize;
193         solid = count - hangover;
194         alignment = get_alignment(fd);
195
196         if ((long)orig_buf & (alignment - 1)) {
197                 buf = aligned_malloc(&buf_base, count, alignment);
198                 if (!buf)
199                         return -1;
200         } else
201                 buf = orig_buf;
202
203         r = read(fd, buf, solid);
204         if(r < 0 || r != solid)
205                 goto out;
206
207         if (hangover) {
208                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
209                 if (!hangover_buf)
210                         goto out;
211                 r = read(fd, hangover_buf, bsize);
212                 if (r <  0 || r != bsize)
213                         goto out;
214
215                 memcpy((char *)buf + solid, hangover_buf, hangover);
216         }
217         ret = count;
218 out:
219         free(hangover_buf_base);
220         if (buf != orig_buf) {
221                 memcpy(orig_buf, buf, count);
222                 free(buf_base);
223         }
224         return ret;
225 }
226
227 /*
228  * Combines llseek with blockwise write. write_blockwise can already deal with short writes
229  * but we also need a function to deal with short writes at the start. But this information
230  * is implicitly included in the read/write offset, which can not be set to non-aligned
231  * boundaries. Hence, we combine llseek with write.
232  */
233 ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) {
234         char *frontPadBuf;
235         void *frontPadBuf_base = NULL;
236         int r, bsize, frontHang;
237         size_t innerCount = 0;
238         ssize_t ret = -1;
239
240         if ((bsize = sector_size(fd)) < 0)
241                 return bsize;
242
243         frontHang = offset % bsize;
244
245         if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
246                 goto out;
247
248         if (frontHang) {
249                 frontPadBuf = aligned_malloc(&frontPadBuf_base,
250                                              bsize, get_alignment(fd));
251                 if (!frontPadBuf)
252                         goto out;
253
254                 r = read(fd, frontPadBuf, bsize);
255                 if (r < 0 || r != bsize)
256                         goto out;
257
258                 innerCount = bsize - frontHang;
259                 if (innerCount > count)
260                         innerCount = count;
261
262                 memcpy(frontPadBuf + frontHang, buf, innerCount);
263
264                 if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
265                         goto out;
266
267                 r = write(fd, frontPadBuf, bsize);
268                 if (r < 0 || r != bsize)
269                         goto out;
270
271                 buf += innerCount;
272                 count -= innerCount;
273         }
274
275         ret = count ? write_blockwise(fd, buf, count) : 0;
276         if (ret >= 0)
277                 ret += innerCount;
278 out:
279         free(frontPadBuf_base);
280
281         return ret;
282 }
283
284 int device_ready(struct crypt_device *cd, const char *device, int mode)
285 {
286         int devfd, r = 0;
287         ssize_t s;
288         struct stat st;
289         char buf[512];
290
291         if(stat(device, &st) < 0) {
292                 log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
293                 return -EINVAL;
294         }
295
296         if (!S_ISBLK(st.st_mode))
297                 return -ENOTBLK;
298
299         log_dbg("Trying to open and read device %s.", device);
300         devfd = open(device, mode | O_DIRECT | O_SYNC);
301         if(devfd < 0) {
302                 log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
303                         (mode & O_EXCL) ? _("exclusive ") : "",
304                         (mode & O_RDWR) ? _("writable") : _("read-only"));
305                 return -EINVAL;
306         }
307
308          /* Try to read first sector */
309         s = read_blockwise(devfd, buf, sizeof(buf));
310         if (s < 0 || s != sizeof(buf)) {
311                 log_verbose(cd, _("Cannot read device %s.\n"), device);
312                 r = -EIO;
313         }
314
315         memset(buf, 0, sizeof(buf));
316         close(devfd);
317
318         return r;
319 }
320
321 int get_device_infos(const char *device,
322                      int open_exclusive,
323                      int *readonly,
324                      uint64_t *size)
325 {
326         struct stat st;
327         unsigned long size_small;
328         int fd, r = -1;
329         int flags = 0;
330
331         *readonly = 0;
332         *size = 0;
333
334         if (stat(device, &st) < 0)
335                 return -EINVAL;
336
337         /* never wipe header on mounted device */
338         if (open_exclusive && S_ISBLK(st.st_mode))
339                 flags |= O_EXCL;
340
341         /* Try to open read-write to check whether it is a read-only device */
342         fd = open(device, O_RDWR | flags);
343         if (fd == -1 && errno == EROFS) {
344                 *readonly = 1;
345                 fd = open(device, O_RDONLY | flags);
346         }
347
348         if (fd == -1 && open_exclusive && errno == EBUSY)
349                 return -EBUSY;
350
351         if (fd == -1)
352                 return -EINVAL;
353
354 #ifdef BLKROGET
355         /* If the device can be opened read-write, i.e. readonly is still 0, then
356          * check whether BKROGET says that it is read-only. E.g. read-only loop
357          * devices may be openend read-write but are read-only according to BLKROGET
358          */
359         if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
360                 goto out;
361 #else
362 #error BLKROGET not available
363 #endif
364
365 #ifdef BLKGETSIZE64
366         if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
367                 *size >>= SECTOR_SHIFT;
368                 r = 0;
369                 goto out;
370         }
371 #endif
372
373 #ifdef BLKGETSIZE
374         if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
375                 *size = (uint64_t)size_small;
376                 r = 0;
377                 goto out;
378         }
379
380 #else
381 #       error Need at least the BLKGETSIZE ioctl!
382 #endif
383         r = -EINVAL;
384 out:
385         close(fd);
386         return r;
387 }
388
389 int device_check_and_adjust(struct crypt_device *cd,
390                             const char *device,
391                             int open_exclusive,
392                             uint64_t *size,
393                             uint64_t *offset,
394                             int *read_only)
395 {
396         int r, real_readonly;
397         uint64_t real_size;
398
399         if (!device)
400                 return -ENOTBLK;
401
402         r = get_device_infos(device, open_exclusive, &real_readonly, &real_size);
403         if (r < 0) {
404                 if (r == -EBUSY)
405                         log_err(cd, _("Cannot use device %s which is in use "
406                                       "(already mapped or mounted).\n"),
407                                       device);
408                 else
409                         log_err(cd, _("Cannot get info about device %s.\n"),
410                                 device);
411                 return r;
412         }
413
414         if (!*size) {
415                 *size = real_size;
416                 if (!*size) {
417                         log_err(cd, _("Device %s has zero size.\n"), device);
418                         return -ENOTBLK;
419                 }
420                 if (*size < *offset) {
421                         log_err(cd, _("Device %s is too small.\n"), device);
422                         return -EINVAL;
423                 }
424                 *size -= *offset;
425         }
426
427         if (real_readonly)
428                 *read_only = 1;
429
430         log_dbg("Calculated device size is %" PRIu64 " sectors (%s), offset %" PRIu64 ".",
431                 *size, *read_only ? "RO" : "RW", *offset);
432         return 0;
433 }
434
435 int wipe_device_header(const char *device, int sectors)
436 {
437         struct stat st;
438         char *buffer;
439         int size = sectors * SECTOR_SIZE;
440         int r = -1;
441         int devfd;
442         int flags = O_RDWR | O_DIRECT | O_SYNC;
443
444         if (stat(device, &st) < 0)
445                 return -EINVAL;
446
447         /* never wipe header on mounted device */
448         if (S_ISBLK(st.st_mode))
449                 flags |= O_EXCL;
450
451         devfd = open(device, flags);
452         if(devfd == -1)
453                 return errno == EBUSY ? -EBUSY : -EINVAL;
454
455         buffer = malloc(size);
456         if (!buffer) {
457                 close(devfd);
458                 return -ENOMEM;
459         }
460         memset(buffer, 0, size);
461
462         r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0;
463
464         free(buffer);
465         close(devfd);
466
467         return r;
468 }
469
470 /* MEMLOCK */
471 #define DEFAULT_PROCESS_PRIORITY -18
472
473 static int _priority;
474 static int _memlock_count = 0;
475
476 // return 1 if memory is locked
477 int crypt_memlock_inc(struct crypt_device *ctx)
478 {
479         if (!_memlock_count++) {
480                 log_dbg("Locking memory.");
481                 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
482                         log_err(ctx, _("WARNING!!! Possibly insecure memory. Are you root?\n"));
483                         _memlock_count--;
484                         return 0;
485                 }
486                 errno = 0;
487                 if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
488                         log_err(ctx, _("Cannot get process priority.\n"));
489                 else
490                         if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
491                                 log_err(ctx, _("setpriority %d failed: %s\n"),
492                                         DEFAULT_PROCESS_PRIORITY, strerror(errno));
493         }
494         return _memlock_count ? 1 : 0;
495 }
496
497 int crypt_memlock_dec(struct crypt_device *ctx)
498 {
499         if (_memlock_count && (!--_memlock_count)) {
500                 log_dbg("Unlocking memory.");
501                 if (munlockall() == -1)
502                         log_err(ctx, _("Cannot unlock memory.\n"));
503                 if (setpriority(PRIO_PROCESS, 0, _priority))
504                         log_err(ctx, _("setpriority %d failed: %s\n"), _priority, strerror(errno));
505         }
506         return _memlock_count ? 1 : 0;
507 }
508
509 /* DEVICE TOPOLOGY */
510
511 /* block device topology ioctls, introduced in 2.6.32 */
512 #ifndef BLKIOMIN
513 #define BLKIOMIN    _IO(0x12,120)
514 #define BLKIOOPT    _IO(0x12,121)
515 #define BLKALIGNOFF _IO(0x12,122)
516 #endif
517
518 void get_topology_alignment(const char *device,
519                             unsigned long *required_alignment, /* bytes */
520                             unsigned long *alignment_offset,   /* bytes */
521                             unsigned long default_alignment)
522 {
523         int dev_alignment_offset = 0;
524         unsigned int min_io_size = 0, opt_io_size = 0;
525         unsigned long temp_alignment = 0;
526         int fd;
527
528         *required_alignment = default_alignment;
529         *alignment_offset = 0;
530
531         fd = open(device, O_RDONLY);
532         if (fd == -1)
533                 return;
534
535         /* minimum io size */
536         if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
537                 log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
538                         device, default_alignment);
539                 goto out;
540         }
541
542         /* optimal io size */
543         if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
544                 opt_io_size = min_io_size;
545
546         /* alignment offset, bogus -1 means misaligned/unknown */
547         if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
548                 dev_alignment_offset = 0;
549         *alignment_offset = (unsigned long)dev_alignment_offset;
550
551         temp_alignment = (unsigned long)min_io_size;
552
553         if (temp_alignment < (unsigned long)opt_io_size)
554                 temp_alignment = (unsigned long)opt_io_size;
555
556         /* If calculated alignment is multiple of default, keep default */
557         if (temp_alignment && (default_alignment % temp_alignment))
558                 *required_alignment = temp_alignment;
559
560         log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
561                 min_io_size, opt_io_size, *alignment_offset, *required_alignment);
562 out:
563         (void)close(fd);
564 }