Fix requested_type description in header.
[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-2012, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 int get_alignment(int fd)
42 {
43         int alignment = DEFAULT_MEM_ALIGNMENT;
44
45 #ifdef _PC_REC_XFER_ALIGN
46         alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
47         if (alignment < 0)
48                 alignment = DEFAULT_MEM_ALIGNMENT;
49 #endif
50         return alignment;
51 }
52
53 static void *aligned_malloc(void **base, int size, int alignment)
54 {
55 #ifdef HAVE_POSIX_MEMALIGN
56         return posix_memalign(base, alignment, size) ? NULL : *base;
57 #else
58 /* Credits go to Michal's padlock patches for this alignment code */
59         char *ptr;
60
61         ptr  = malloc(size + alignment);
62         if(ptr == NULL) return NULL;
63
64         *base = ptr;
65         if(alignment > 1 && ((long)ptr & (alignment - 1))) {
66                 ptr += alignment - ((long)(ptr) & (alignment - 1));
67         }
68         return ptr;
69 #endif
70 }
71
72 int device_read_ahead(const char *dev, uint32_t *read_ahead)
73 {
74         int fd, r = 0;
75         long read_ahead_long;
76
77         if ((fd = open(dev, O_RDONLY)) < 0)
78                 return 0;
79
80         r = ioctl(fd, BLKRAGET, &read_ahead_long) ? 0 : 1;
81         close(fd);
82
83         if (r)
84                 *read_ahead = (uint32_t) read_ahead_long;
85
86         return r;
87 }
88
89 static int sector_size(int fd) 
90 {
91         int bsize;
92         if (ioctl(fd,BLKSSZGET, &bsize) < 0)
93                 return -EINVAL;
94         else
95                 return bsize;
96 }
97
98 int sector_size_for_device(const char *device)
99 {
100         int fd = open(device, O_RDONLY);
101         int r;
102         if(fd < 0)
103                 return -EINVAL;
104         r = sector_size(fd);
105         close(fd);
106         return r;
107 }
108
109 ssize_t write_blockwise(int fd, void *orig_buf, size_t count)
110 {
111         void *hangover_buf, *hangover_buf_base = NULL;
112         void *buf, *buf_base = NULL;
113         int r, hangover, solid, bsize, alignment;
114         ssize_t ret = -1;
115
116         if ((bsize = sector_size(fd)) < 0)
117                 return bsize;
118
119         hangover = count % bsize;
120         solid = count - hangover;
121         alignment = get_alignment(fd);
122
123         if ((long)orig_buf & (alignment - 1)) {
124                 buf = aligned_malloc(&buf_base, count, alignment);
125                 if (!buf)
126                         goto out;
127                 memcpy(buf, orig_buf, count);
128         } else
129                 buf = orig_buf;
130
131         r = write(fd, buf, solid);
132         if (r < 0 || r != solid)
133                 goto out;
134
135         if (hangover) {
136                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
137                 if (!hangover_buf)
138                         goto out;
139
140                 r = read(fd, hangover_buf, bsize);
141                 if (r < 0 || r != bsize)
142                         goto out;
143
144                 r = lseek(fd, -bsize, SEEK_CUR);
145                 if (r < 0)
146                         goto out;
147                 memcpy(hangover_buf, (char*)buf + solid, hangover);
148
149                 r = write(fd, hangover_buf, bsize);
150                 if (r < 0 || r != bsize)
151                         goto out;
152         }
153         ret = count;
154 out:
155         free(hangover_buf_base);
156         if (buf != orig_buf)
157                 free(buf_base);
158         return ret;
159 }
160
161 ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
162         void *hangover_buf, *hangover_buf_base = NULL;
163         void *buf, *buf_base = NULL;
164         int r, hangover, solid, bsize, alignment;
165         ssize_t ret = -1;
166
167         if ((bsize = sector_size(fd)) < 0)
168                 return bsize;
169
170         hangover = count % bsize;
171         solid = count - hangover;
172         alignment = get_alignment(fd);
173
174         if ((long)orig_buf & (alignment - 1)) {
175                 buf = aligned_malloc(&buf_base, count, alignment);
176                 if (!buf)
177                         return -1;
178         } else
179                 buf = orig_buf;
180
181         r = read(fd, buf, solid);
182         if(r < 0 || r != solid)
183                 goto out;
184
185         if (hangover) {
186                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
187                 if (!hangover_buf)
188                         goto out;
189                 r = read(fd, hangover_buf, bsize);
190                 if (r <  0 || r != bsize)
191                         goto out;
192
193                 memcpy((char *)buf + solid, hangover_buf, hangover);
194         }
195         ret = count;
196 out:
197         free(hangover_buf_base);
198         if (buf != orig_buf) {
199                 memcpy(orig_buf, buf, count);
200                 free(buf_base);
201         }
202         return ret;
203 }
204
205 /*
206  * Combines llseek with blockwise write. write_blockwise can already deal with short writes
207  * but we also need a function to deal with short writes at the start. But this information
208  * is implicitly included in the read/write offset, which can not be set to non-aligned
209  * boundaries. Hence, we combine llseek with write.
210  */
211 ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) {
212         char *frontPadBuf;
213         void *frontPadBuf_base = NULL;
214         int r, bsize, frontHang;
215         size_t innerCount = 0;
216         ssize_t ret = -1;
217
218         if ((bsize = sector_size(fd)) < 0)
219                 return bsize;
220
221         frontHang = offset % bsize;
222
223         if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
224                 goto out;
225
226         if (frontHang) {
227                 frontPadBuf = aligned_malloc(&frontPadBuf_base,
228                                              bsize, get_alignment(fd));
229                 if (!frontPadBuf)
230                         goto out;
231
232                 r = read(fd, frontPadBuf, bsize);
233                 if (r < 0 || r != bsize)
234                         goto out;
235
236                 innerCount = bsize - frontHang;
237                 if (innerCount > count)
238                         innerCount = count;
239
240                 memcpy(frontPadBuf + frontHang, buf, innerCount);
241
242                 if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
243                         goto out;
244
245                 r = write(fd, frontPadBuf, bsize);
246                 if (r < 0 || r != bsize)
247                         goto out;
248
249                 buf += innerCount;
250                 count -= innerCount;
251         }
252
253         ret = count ? write_blockwise(fd, buf, count) : 0;
254         if (ret >= 0)
255                 ret += innerCount;
256 out:
257         free(frontPadBuf_base);
258
259         return ret;
260 }
261
262 int device_ready(struct crypt_device *cd, const char *device, int mode)
263 {
264         int devfd, r = 0;
265         ssize_t s;
266         struct stat st;
267         char buf[512];
268
269         if(stat(device, &st) < 0) {
270                 log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
271                 return -EINVAL;
272         }
273
274         if (!S_ISBLK(st.st_mode))
275                 return -ENOTBLK;
276
277         log_dbg("Trying to open and read device %s.", device);
278         devfd = open(device, mode | O_DIRECT | O_SYNC);
279         if(devfd < 0) {
280                 log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
281                         (mode & O_EXCL) ? _("exclusive ") : "",
282                         (mode & O_RDWR) ? _("writable") : _("read-only"));
283                 return -EINVAL;
284         }
285
286          /* Try to read first sector */
287         s = read_blockwise(devfd, buf, sizeof(buf));
288         if (s < 0 || s != sizeof(buf)) {
289                 log_verbose(cd, _("Cannot read device %s.\n"), device);
290                 r = -EIO;
291         }
292
293         memset(buf, 0, sizeof(buf));
294         close(devfd);
295
296         return r;
297 }
298
299 int device_size(const char *device, uint64_t *size)
300 {
301         int devfd, r = 0;
302
303         devfd = open(device, O_RDONLY);
304         if(devfd == -1)
305                 return -EINVAL;
306
307         if (ioctl(devfd, BLKGETSIZE64, size) < 0)
308                 r = -EINVAL;
309
310         close(devfd);
311         return r;
312 }
313
314 static int get_device_infos(const char *device, enum devcheck device_check,
315                             int *readonly, uint64_t *size)
316 {
317         struct stat st;
318         unsigned long size_small;
319         int fd, r = -1;
320         int flags = 0;
321
322         *readonly = 0;
323         *size = 0;
324
325         if (stat(device, &st) < 0)
326                 return -EINVAL;
327
328         /* never wipe header on mounted device */
329         if (device_check == DEV_EXCL && S_ISBLK(st.st_mode))
330                 flags |= O_EXCL;
331
332         /* Try to open read-write to check whether it is a read-only device */
333         fd = open(device, O_RDWR | flags);
334         if (fd == -1 && errno == EROFS) {
335                 *readonly = 1;
336                 fd = open(device, O_RDONLY | flags);
337         }
338
339         if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
340                 return -EBUSY;
341
342         if (fd == -1)
343                 return -EINVAL;
344
345         /* If the device can be opened read-write, i.e. readonly is still 0, then
346          * check whether BKROGET says that it is read-only. E.g. read-only loop
347          * devices may be openend read-write but are read-only according to BLKROGET
348          */
349         if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
350                 goto out;
351
352         if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
353                 *size >>= SECTOR_SHIFT;
354                 r = 0;
355                 goto out;
356         }
357
358         if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
359                 *size = (uint64_t)size_small;
360                 r = 0;
361                 goto out;
362         }
363
364         r = -EINVAL;
365 out:
366         close(fd);
367         return r;
368 }
369
370 int device_check_and_adjust(struct crypt_device *cd,
371                             const char *device,
372                             enum devcheck device_check,
373                             uint64_t *size,
374                             uint64_t *offset,
375                             uint32_t *flags)
376 {
377         int r, real_readonly;
378         uint64_t real_size;
379
380         if (!device)
381                 return -ENOTBLK;
382
383         r = get_device_infos(device, device_check, &real_readonly, &real_size);
384         if (r < 0) {
385                 if (r == -EBUSY)
386                         log_err(cd, _("Cannot use device %s which is in use "
387                                       "(already mapped or mounted).\n"),
388                                       device);
389                 else
390                         log_err(cd, _("Cannot get info about device %s.\n"),
391                                 device);
392                 return r;
393         }
394
395         if (*offset >= real_size) {
396                 log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
397                         device);
398                 return -EINVAL;
399         }
400
401         if (!*size) {
402                 *size = real_size;
403                 if (!*size) {
404                         log_err(cd, _("Device %s has zero size.\n"), device);
405                         return -ENOTBLK;
406                 }
407                 *size -= *offset;
408         }
409
410         /* in case of size is set by parameter */
411         if ((real_size - *offset) < *size) {
412                 log_dbg("Device %s: offset = %" PRIu64 " requested size = %" PRIu64
413                         ", backing device size = %" PRIu64,
414                         device, *offset, *size, real_size);
415                 log_err(cd, _("Device %s is too small.\n"), device);
416                 return -EINVAL;
417         }
418
419         if (device_check == DEV_SHARED) {
420                 log_dbg("Checking crypt segments for device %s.", device);
421                 r = crypt_sysfs_check_crypt_segment(device, *offset, *size);
422                 if (r < 0) {
423                         log_err(cd, _("Cannot use device %s (crypt segments "
424                                     "overlaps or in use by another device).\n"),
425                                     device);
426                         return r;
427                 }
428         }
429
430         if (real_readonly)
431                 *flags |= CRYPT_ACTIVATE_READONLY;
432
433         log_dbg("Calculated device size is %" PRIu64 " sectors (%s), offset %" PRIu64 ".",
434                 *size, real_readonly ? "RO" : "RW", *offset);
435         return 0;
436 }
437
438 /* MEMLOCK */
439 #define DEFAULT_PROCESS_PRIORITY -18
440
441 static int _priority;
442 static int _memlock_count = 0;
443
444 // return 1 if memory is locked
445 int crypt_memlock_inc(struct crypt_device *ctx)
446 {
447         if (!_memlock_count++) {
448                 log_dbg("Locking memory.");
449                 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
450                         log_err(ctx, _("WARNING!!! Possibly insecure memory. Are you root?\n"));
451                         _memlock_count--;
452                         return 0;
453                 }
454                 errno = 0;
455                 if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
456                         log_err(ctx, _("Cannot get process priority.\n"));
457                 else
458                         if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
459                                 log_err(ctx, _("setpriority %d failed: %s\n"),
460                                         DEFAULT_PROCESS_PRIORITY, strerror(errno));
461         }
462         return _memlock_count ? 1 : 0;
463 }
464
465 int crypt_memlock_dec(struct crypt_device *ctx)
466 {
467         if (_memlock_count && (!--_memlock_count)) {
468                 log_dbg("Unlocking memory.");
469                 if (munlockall() == -1)
470                         log_err(ctx, _("Cannot unlock memory.\n"));
471                 if (setpriority(PRIO_PROCESS, 0, _priority))
472                         log_err(ctx, _("setpriority %d failed: %s\n"), _priority, strerror(errno));
473         }
474         return _memlock_count ? 1 : 0;
475 }
476
477 /* DEVICE TOPOLOGY */
478
479 /* block device topology ioctls, introduced in 2.6.32 */
480 #ifndef BLKIOMIN
481 #define BLKIOMIN    _IO(0x12,120)
482 #define BLKIOOPT    _IO(0x12,121)
483 #define BLKALIGNOFF _IO(0x12,122)
484 #endif
485
486 void get_topology_alignment(const char *device,
487                             unsigned long *required_alignment, /* bytes */
488                             unsigned long *alignment_offset,   /* bytes */
489                             unsigned long default_alignment)
490 {
491         int dev_alignment_offset = 0;
492         unsigned int min_io_size = 0, opt_io_size = 0;
493         unsigned long temp_alignment = 0;
494         int fd;
495
496         *required_alignment = default_alignment;
497         *alignment_offset = 0;
498
499         fd = open(device, O_RDONLY);
500         if (fd == -1)
501                 return;
502
503         /* minimum io size */
504         if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
505                 log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
506                         device, default_alignment);
507                 goto out;
508         }
509
510         /* optimal io size */
511         if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
512                 opt_io_size = min_io_size;
513
514         /* alignment offset, bogus -1 means misaligned/unknown */
515         if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
516                 dev_alignment_offset = 0;
517         *alignment_offset = (unsigned long)dev_alignment_offset;
518
519         temp_alignment = (unsigned long)min_io_size;
520
521         if (temp_alignment < (unsigned long)opt_io_size)
522                 temp_alignment = (unsigned long)opt_io_size;
523
524         /* If calculated alignment is multiple of default, keep default */
525         if (temp_alignment && (default_alignment % temp_alignment))
526                 *required_alignment = temp_alignment;
527
528         log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
529                 min_io_size, opt_io_size, *alignment_offset, *required_alignment);
530 out:
531         (void)close(fd);
532 }