1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <fs_dm.h>
17 #include "securec.h"
18 #include "beget_ext.h"
19 #include <linux/dm-ioctl.h>
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/sysmacros.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include "ueventd.h"
27 #include "ueventd_socket.h"
28 #include <limits.h>
29
30 #ifdef __cplusplus
31 #if __cplusplus
32 extern "C" {
33 #endif
34 #endif
35
36 #define DM_VERSION0 (4)
37 #define DM_VERSION1 (0)
38 #define DM_VERSION2 (0)
39 #define DM_ALIGN_MASK (7)
40 #define DM_ALIGN(x) (((x) + DM_ALIGN_MASK) & ~DM_ALIGN_MASK)
41 #define DEVICE_MAPPER_PATH "/dev/mapper/control"
42 #define DM_DEVICE_PATH_PREFIX "/dev/block/dm-"
43
44 #define FS_DM_RETURN_ERR_IF_NULL(__ptr) \
45 do { \
46 if ((__ptr) == NULL) { \
47 BEGET_LOGE("error, %s is NULL\n", #__ptr); \
48 return -1; \
49 } \
50 } while (0)
51
InitDmIo(struct dm_ioctl * io,const char * devName)52 static int InitDmIo(struct dm_ioctl *io, const char *devName)
53 {
54 errno_t err;
55
56 err = memset_s(io, sizeof(*io), 0, sizeof(*io));
57 if (err != EOK) {
58 BEGET_LOGE("memset io, ret=%d", err);
59 return -1;
60 }
61
62 io->version[0] = DM_VERSION0;
63 io->version[1] = DM_VERSION1;
64 io->version[2] = DM_VERSION2;
65 io->data_size = sizeof(*io);
66 io->data_start = 0;
67
68 if (devName == NULL) {
69 return 0;
70 }
71
72 err = strcpy_s(io->name, sizeof(io->name), devName);
73 if (err != EOK) {
74 BEGET_LOGE("cp devName, ret=%d", err);
75 return -1;
76 }
77
78 return 0;
79 }
80
CreateDmDevice(int fd,const char * devName)81 static int CreateDmDevice(int fd, const char *devName)
82 {
83 int rc;
84 struct dm_ioctl io;
85
86 rc = InitDmIo(&io, devName);
87 if (rc != 0) {
88 return rc;
89 }
90
91 rc = ioctl(fd, DM_DEV_CREATE, &io);
92 if (rc != 0) {
93 BEGET_LOGE("error, DM_DEV_CREATE failed for %s, ret=%d", devName, rc);
94 return rc;
95 }
96
97 return 0;
98 }
99
LoadDmDeviceTable(int fd,const char * devName,DmVerityTarget * target)100 static int LoadDmDeviceTable(int fd, const char *devName,
101 DmVerityTarget *target)
102 {
103 int rc;
104 errno_t err;
105 char *parasBuf = NULL;
106 size_t parasTotalSize;
107 struct dm_ioctl *io = NULL;
108 struct dm_target_spec *ts = NULL;
109 char *paras = NULL;
110
111 FS_DM_RETURN_ERR_IF_NULL(target);
112 FS_DM_RETURN_ERR_IF_NULL(target->paras);
113
114 parasTotalSize = DM_ALIGN(sizeof(*io) + sizeof(*ts) + target->paras_len + 1);
115 parasBuf = calloc(1, parasTotalSize);
116 if (parasBuf == NULL) {
117 BEGET_LOGE("error, calloc dm table fail");
118 return -1;
119 }
120
121 io = (struct dm_ioctl *)parasBuf;
122 ts = (struct dm_target_spec *)(parasBuf + sizeof(*io));
123 paras = parasBuf + sizeof(*io) + sizeof((*ts));
124
125 do {
126 rc = InitDmIo(io, devName);
127 if (rc != 0) {
128 BEGET_LOGE("error 0x%x, init dm io", rc);
129 break;
130 }
131
132 io->data_size = parasTotalSize;
133 io->data_start = sizeof(*io);
134 io->target_count = 1;
135 io->flags |= DM_READONLY_FLAG;
136
137 ts->status = 0;
138 ts->sector_start = target->start;
139 ts->length = target->length;
140
141 err = strcpy_s(ts->target_type, sizeof(ts->target_type), "verity");
142 if (err != EOK) {
143 rc = -1;
144 BEGET_LOGE("error 0x%x, cp target type", err);
145 break;
146 }
147
148 err = strcpy_s(paras, target->paras_len + 1,target->paras);
149 if (err != EOK) {
150 rc = -1;
151 BEGET_LOGE("error 0x%x, cp target paras", err);
152 break;
153 }
154
155 ts->next = parasTotalSize - sizeof(*io);
156
157 rc = ioctl(fd, DM_TABLE_LOAD, io);
158 if (rc != 0) {
159 BEGET_LOGE("error 0x%x, DM_TABLE_LOAD failed for %s", rc, devName);
160 break;
161 }
162 } while (0);
163
164 free(parasBuf);
165
166 return rc;
167 }
168
ActiveDmDevice(int fd,const char * devName)169 static int ActiveDmDevice(int fd, const char *devName)
170 {
171 int rc;
172 struct dm_ioctl io;
173
174 rc = InitDmIo(&io, devName);
175 if (rc != 0) {
176 return rc;
177 }
178
179 io.flags |= DM_READONLY_FLAG;
180
181 rc = ioctl(fd, DM_DEV_SUSPEND, &io);
182 if (rc != 0) {
183 BEGET_LOGE("error, DM_TABLE_SUSPEND for %s, ret=%d", devName, rc);
184 return rc;
185 }
186
187 return 0;
188 }
189
GetDmDevPath(int fd,char ** dmDevPath,const char * devName)190 int GetDmDevPath(int fd, char **dmDevPath, const char *devName)
191 {
192 int rc;
193 char *path = NULL;
194 size_t path_len = strlen(DM_DEVICE_PATH_PREFIX) + 32;
195 unsigned int dev_num;
196 struct dm_ioctl io;
197
198 rc = InitDmIo(&io, devName);
199 if (rc != 0) {
200 BEGET_LOGE("error 0x%x, init Dm io", rc);
201 return rc;
202 }
203
204 rc = ioctl(fd, DM_DEV_STATUS, &io);
205 if (rc != 0) {
206 BEGET_LOGE("error, DM_DEV_STATUS for %s, ret=%d", devName, rc);
207 return rc;
208 }
209
210 dev_num = minor(io.dev);
211
212 path = calloc(1, path_len);
213 if (path == NULL) {
214 BEGET_LOGE("error, alloc dm dev path");
215 return -1;
216 }
217
218 rc = snprintf_s(path, path_len, path_len - 1, "%s%u", DM_DEVICE_PATH_PREFIX, dev_num);
219 if (rc < 0) {
220 BEGET_LOGE("error 0x%x, cp dm dev path", rc);
221 free(path);
222 return -1;
223 }
224
225 *dmDevPath = path;
226
227 return 0;
228 }
229
FsDmCreateDevice(char ** dmDevPath,const char * devName,DmVerityTarget * target)230 int FsDmCreateDevice(char **dmDevPath, const char *devName, DmVerityTarget *target)
231 {
232 int rc;
233 int fd = -1;
234
235 fd = open(DEVICE_MAPPER_PATH, O_RDWR | O_CLOEXEC);
236 if (fd < 0) {
237 BEGET_LOGE("error 0x%x, open %s", errno, DEVICE_MAPPER_PATH);
238 return -1;
239 }
240
241 rc = CreateDmDevice(fd, devName);
242 if (rc != 0) {
243 BEGET_LOGE("error 0x%x, create dm device fail", rc);
244 return rc;
245 }
246
247 rc = LoadDmDeviceTable(fd, devName, target);
248 if (rc != 0) {
249 BEGET_LOGE("error 0x%x, load device table fail", rc);
250 return rc;
251 }
252
253 rc = ActiveDmDevice(fd, devName);
254 if (rc != 0) {
255 BEGET_LOGE("error 0x%x, active device fail", rc);
256 return rc;
257 }
258
259 rc = GetDmDevPath(fd, dmDevPath, devName);
260 if (rc != 0) {
261 BEGET_LOGE("error 0x%x, get dm dev fail", rc);
262 return rc;
263 }
264
265 return 0;
266 }
267
FsDmInitDmDev(char * devPath)268 int FsDmInitDmDev(char *devPath)
269 {
270 int rc;
271 char dmDevPath[PATH_MAX] = {0};
272 char *devName = NULL;
273
274 if (devPath == NULL) {
275 BEGET_LOGE("error, devPath is NULL");
276 return -1;
277 }
278
279 devName = basename(devPath);
280
281 rc = snprintf_s(&dmDevPath[0], sizeof(dmDevPath), sizeof(dmDevPath) - 1, "%s%s", "/sys/block/", devName);
282 if (rc < 0) {
283 BEGET_LOGE("error 0x%x, format dm dev", rc);
284 return rc;
285 }
286
287 int ueventSockFd = UeventdSocketInit();
288 if (ueventSockFd < 0) {
289 BEGET_LOGE("error, Failed to create uevent socket");
290 return -1;
291 }
292
293 RetriggerUeventByPath(ueventSockFd, &dmDevPath[0]);
294
295 close(ueventSockFd);
296
297 return 0;
298 }
299
300 #ifdef __cplusplus
301 #if __cplusplus
302 }
303 #endif
304 #endif
305