• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <stdlib.h>
26 
27 #include <sys/types.h>
28 #include <sys/ioctl.h>
29 #include <sys/stat.h>
30 
31 #include <linux/kdev_t.h>
32 
33 #include <android-base/logging.h>
34 #include <android-base/strings.h>
35 #include <android-base/stringprintf.h>
36 #include <utils/Trace.h>
37 
38 #include "Devmapper.h"
39 
40 #define DEVMAPPER_BUFFER_SIZE 4096
41 
42 using android::base::StringPrintf;
43 
44 static const char* kVoldPrefix = "vold:";
45 
ioctlInit(struct dm_ioctl * io,size_t dataSize,const char * name,unsigned flags)46 void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize,
47                           const char *name, unsigned flags) {
48     memset(io, 0, dataSize);
49     io->data_size = dataSize;
50     io->data_start = sizeof(struct dm_ioctl);
51     io->version[0] = 4;
52     io->version[1] = 0;
53     io->version[2] = 0;
54     io->flags = flags;
55     if (name) {
56         size_t ret = strlcpy(io->name, name, sizeof(io->name));
57         if (ret >= sizeof(io->name))
58             abort();
59     }
60 }
61 
create(const char * name_raw,const char * loopFile,const char * key,unsigned long numSectors,char * ubuffer,size_t len)62 int Devmapper::create(const char *name_raw, const char *loopFile, const char *key,
63                       unsigned long numSectors, char *ubuffer, size_t len) {
64     auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
65     const char* name = name_string.c_str();
66 
67     char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
68     if (!buffer) {
69         PLOG(ERROR) << "Failed malloc";
70         return -1;
71     }
72 
73     int fd;
74     if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
75         PLOG(ERROR) << "Failed open";
76         free(buffer);
77         return -1;
78     }
79 
80     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
81 
82     // Create the DM device
83     ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
84 
85     if (ioctl(fd, DM_DEV_CREATE, io)) {
86         PLOG(ERROR) << "Failed DM_DEV_CREATE";
87         free(buffer);
88         close(fd);
89         return -1;
90     }
91 
92     // Set the legacy geometry
93     ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
94 
95     char *geoParams = buffer + sizeof(struct dm_ioctl);
96     // bps=512 spc=8 res=32 nft=2 sec=8190 mid=0xf0 spt=63 hds=64 hid=0 bspf=8 rdcl=2 infs=1 bkbs=2
97     strlcpy(geoParams, "0 64 63 0", DEVMAPPER_BUFFER_SIZE - sizeof(struct dm_ioctl));
98     geoParams += strlen(geoParams) + 1;
99     geoParams = (char *) _align(geoParams, 8);
100     if (ioctl(fd, DM_DEV_SET_GEOMETRY, io)) {
101         PLOG(ERROR) << "Failed DM_DEV_SET_GEOMETRY";
102         free(buffer);
103         close(fd);
104         return -1;
105     }
106 
107     // Retrieve the device number we were allocated
108     ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
109     if (ioctl(fd, DM_DEV_STATUS, io)) {
110         PLOG(ERROR) << "Failed DM_DEV_STATUS";
111         free(buffer);
112         close(fd);
113         return -1;
114     }
115 
116     unsigned minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
117     snprintf(ubuffer, len, "/dev/block/dm-%u", minor);
118 
119     // Load the table
120     struct dm_target_spec *tgt;
121     tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
122 
123     ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, DM_STATUS_TABLE_FLAG);
124     io->target_count = 1;
125     tgt->status = 0;
126 
127     tgt->sector_start = 0;
128     tgt->length = numSectors;
129 
130     strlcpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
131 
132     char *cryptParams = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
133     snprintf(cryptParams,
134             DEVMAPPER_BUFFER_SIZE - (sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec)),
135             "twofish %s 0 %s 0", key, loopFile);
136     cryptParams += strlen(cryptParams) + 1;
137     cryptParams = (char *) _align(cryptParams, 8);
138     tgt->next = cryptParams - buffer;
139 
140     if (ioctl(fd, DM_TABLE_LOAD, io)) {
141         PLOG(ERROR) << "Failed DM_TABLE_LOAD";
142         free(buffer);
143         close(fd);
144         return -1;
145     }
146 
147     // Resume the new table
148     ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
149 
150     if (ioctl(fd, DM_DEV_SUSPEND, io)) {
151         PLOG(ERROR) << "Failed DM_DEV_SUSPEND";
152         free(buffer);
153         close(fd);
154         return -1;
155     }
156 
157     free(buffer);
158 
159     close(fd);
160     return 0;
161 }
162 
destroy(const char * name_raw)163 int Devmapper::destroy(const char *name_raw) {
164     auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
165     const char* name = name_string.c_str();
166 
167     char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
168     if (!buffer) {
169         PLOG(ERROR) << "Failed malloc";
170         return -1;
171     }
172 
173     int fd;
174     if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
175         PLOG(ERROR) << "Failed open";
176         free(buffer);
177         return -1;
178     }
179 
180     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
181 
182     // Create the DM device
183     ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
184 
185     if (ioctl(fd, DM_DEV_REMOVE, io)) {
186         if (errno != ENXIO) {
187             PLOG(ERROR) << "Failed DM_DEV_REMOVE";
188         }
189         free(buffer);
190         close(fd);
191         return -1;
192     }
193 
194     free(buffer);
195     close(fd);
196     return 0;
197 }
198 
destroyAll()199 int Devmapper::destroyAll() {
200     ATRACE_NAME("Devmapper::destroyAll");
201     char *buffer = (char *) malloc(1024 * 64);
202     if (!buffer) {
203         PLOG(ERROR) << "Failed malloc";
204         return -1;
205     }
206     memset(buffer, 0, (1024 * 64));
207 
208     char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
209     if (!buffer2) {
210         PLOG(ERROR) << "Failed malloc";
211         free(buffer);
212         return -1;
213     }
214 
215     int fd;
216     if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
217         PLOG(ERROR) << "Failed open";
218         free(buffer);
219         free(buffer2);
220         return -1;
221     }
222 
223     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
224     ioctlInit(io, (1024 * 64), NULL, 0);
225 
226     if (ioctl(fd, DM_LIST_DEVICES, io)) {
227         PLOG(ERROR) << "Failed DM_LIST_DEVICES";
228         free(buffer);
229         free(buffer2);
230         close(fd);
231         return -1;
232     }
233 
234     struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start);
235     if (!n->dev) {
236         free(buffer);
237         free(buffer2);
238         close(fd);
239         return 0;
240     }
241 
242     unsigned nxt = 0;
243     do {
244         n = (struct dm_name_list *) (((char *) n) + nxt);
245         auto name = std::string(n->name);
246         if (android::base::StartsWith(name, kVoldPrefix)) {
247             LOG(DEBUG) << "Tearing down stale dm device named " << name;
248 
249             memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
250             struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2;
251             ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
252             if (ioctl(fd, DM_DEV_REMOVE, io2)) {
253                 if (errno != ENXIO) {
254                     PLOG(WARNING) << "Failed to destroy dm device named " << name;
255                 }
256             }
257         } else {
258             LOG(VERBOSE) << "Found unmanaged dm device named " << name;
259         }
260         nxt = n->next;
261     } while (nxt);
262 
263     free(buffer);
264     free(buffer2);
265     close(fd);
266     return 0;
267 }
268 
_align(void * ptr,unsigned int a)269 void *Devmapper::_align(void *ptr, unsigned int a)
270 {
271         unsigned long agn = --a;
272 
273         return (void *) (((unsigned long) ptr + agn) & ~agn);
274 }
275