1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2018 Google LLC
4 */
5 #include <dirent.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <poll.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include <sys/ioctl.h>
15 #include <sys/mount.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18
19 #include <openssl/sha.h>
20 #include <openssl/md5.h>
21
22 #include "utils.h"
23
24 #ifndef __S_IFREG
25 #define __S_IFREG S_IFREG
26 #endif
27
rnd(unsigned int max,unsigned int * seed)28 unsigned int rnd(unsigned int max, unsigned int *seed)
29 {
30 return rand_r(seed) * ((uint64_t)max + 1) / RAND_MAX;
31 }
32
remove_dir(const char * dir)33 int remove_dir(const char *dir)
34 {
35 int err = rmdir(dir);
36
37 if (err && errno == ENOTEMPTY) {
38 err = delete_dir_tree(dir);
39 if (err)
40 return err;
41 return 0;
42 }
43
44 if (err && errno != ENOENT)
45 return -errno;
46
47 return 0;
48 }
49
drop_caches(void)50 int drop_caches(void)
51 {
52 int drop_caches =
53 open("/proc/sys/vm/drop_caches", O_WRONLY | O_CLOEXEC);
54 int i;
55
56 if (drop_caches == -1)
57 return -errno;
58 i = write(drop_caches, "3", 1);
59 close(drop_caches);
60
61 if (i != 1)
62 return -errno;
63
64 return 0;
65 }
66
mount_fs(const char * mount_dir,const char * backing_dir,int read_timeout_ms)67 int mount_fs(const char *mount_dir, const char *backing_dir,
68 int read_timeout_ms)
69 {
70 static const char fs_name[] = INCFS_NAME;
71 char mount_options[512];
72 int result;
73
74 snprintf(mount_options, ARRAY_SIZE(mount_options),
75 "read_timeout_ms=%u",
76 read_timeout_ms);
77
78 result = mount(backing_dir, mount_dir, fs_name, 0, mount_options);
79 if (result != 0)
80 perror("Error mounting fs.");
81 return result;
82 }
83
umount_fs(const char * mount_dir)84 int umount_fs(const char *mount_dir)
85 {
86 int result;
87
88 result = umount(mount_dir);
89 if (result != 0)
90 perror("Error unmounting fs.");
91 return result;
92 }
93
mount_fs_opt(const char * mount_dir,const char * backing_dir,const char * opt,bool remount)94 int mount_fs_opt(const char *mount_dir, const char *backing_dir,
95 const char *opt, bool remount)
96 {
97 static const char fs_name[] = INCFS_NAME;
98 int result;
99
100 result = mount(backing_dir, mount_dir, fs_name,
101 remount ? MS_REMOUNT : 0, opt);
102 if (result != 0)
103 perror("Error mounting fs.");
104 return result;
105 }
106
107 struct hash_section {
108 uint32_t algorithm;
109 uint8_t log2_blocksize;
110 uint32_t salt_size;
111 /* no salt */
112 uint32_t hash_size;
113 uint8_t hash[SHA256_DIGEST_SIZE];
114 } __packed;
115
116 struct signature_blob {
117 uint32_t version;
118 uint32_t hash_section_size;
119 struct hash_section hash_section;
120 uint32_t signing_section_size;
121 uint8_t signing_section[];
122 } __packed;
123
format_signature(void ** buf,const char * root_hash,const char * add_data)124 size_t format_signature(void **buf, const char *root_hash, const char *add_data)
125 {
126 size_t size = sizeof(struct signature_blob) + strlen(add_data) + 1;
127 struct signature_blob *sb = malloc(size);
128
129 if (!sb)
130 return 0;
131
132 *sb = (struct signature_blob){
133 .version = INCFS_SIGNATURE_VERSION,
134 .hash_section_size = sizeof(struct hash_section),
135 .hash_section =
136 (struct hash_section){
137 .algorithm = INCFS_HASH_TREE_SHA256,
138 .log2_blocksize = 12,
139 .salt_size = 0,
140 .hash_size = SHA256_DIGEST_SIZE,
141 },
142 .signing_section_size = strlen(add_data) + 1,
143 };
144
145 memcpy(sb->hash_section.hash, root_hash, SHA256_DIGEST_SIZE);
146 memcpy((char *)sb->signing_section, add_data, strlen(add_data) + 1);
147 *buf = sb;
148 return size;
149 }
150
crypto_emit_file(int fd,const char * dir,const char * filename,incfs_uuid_t * id_out,size_t size,const char * root_hash,const char * add_data)151 int crypto_emit_file(int fd, const char *dir, const char *filename,
152 incfs_uuid_t *id_out, size_t size, const char *root_hash,
153 const char *add_data)
154 {
155 int mode = __S_IFREG | 0555;
156 void *signature;
157 int error = 0;
158
159 struct incfs_new_file_args args = {
160 .size = size,
161 .mode = mode,
162 .file_name = ptr_to_u64(filename),
163 .directory_path = ptr_to_u64(dir),
164 .file_attr = 0,
165 .file_attr_len = 0
166 };
167
168 args.signature_size = format_signature(&signature, root_hash, add_data);
169 args.signature_info = ptr_to_u64(signature);
170
171 md5(filename, strlen(filename), (char *)args.file_id.bytes);
172
173 if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) {
174 error = -errno;
175 goto out;
176 }
177
178 *id_out = args.file_id;
179
180 out:
181 free(signature);
182 return error;
183 }
184
emit_file(int fd,const char * dir,const char * filename,incfs_uuid_t * id_out,size_t size,const char * attr)185 int emit_file(int fd, const char *dir, const char *filename,
186 incfs_uuid_t *id_out, size_t size, const char *attr)
187 {
188 int mode = __S_IFREG | 0555;
189 struct incfs_new_file_args args = { .size = size,
190 .mode = mode,
191 .file_name = ptr_to_u64(filename),
192 .directory_path = ptr_to_u64(dir),
193 .signature_info = ptr_to_u64(NULL),
194 .signature_size = 0,
195 .file_attr = ptr_to_u64(attr),
196 .file_attr_len =
197 attr ? strlen(attr) : 0 };
198
199 md5(filename, strlen(filename), (char *)args.file_id.bytes);
200
201 if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0)
202 return -errno;
203
204 *id_out = args.file_id;
205 return 0;
206 }
207
get_file_bmap(int cmd_fd,int ino,unsigned char * buf,int buf_size)208 int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size)
209 {
210 return 0;
211 }
212
get_file_signature(int fd,unsigned char * buf,int buf_size)213 int get_file_signature(int fd, unsigned char *buf, int buf_size)
214 {
215 struct incfs_get_file_sig_args args = {
216 .file_signature = ptr_to_u64(buf),
217 .file_signature_buf_size = buf_size
218 };
219
220 if (ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &args) == 0)
221 return args.file_signature_len_out;
222 return -errno;
223 }
224
get_file_size(const char * name)225 loff_t get_file_size(const char *name)
226 {
227 struct stat st;
228
229 if (stat(name, &st) == 0)
230 return st.st_size;
231 return -ENOENT;
232 }
233
open_commands_file(const char * mount_dir)234 int open_commands_file(const char *mount_dir)
235 {
236 char cmd_file[255];
237 int cmd_fd;
238
239 snprintf(cmd_file, ARRAY_SIZE(cmd_file),
240 "%s/%s", mount_dir, INCFS_PENDING_READS_FILENAME);
241 cmd_fd = open(cmd_file, O_RDONLY | O_CLOEXEC);
242
243 if (cmd_fd < 0)
244 perror("Can't open commands file");
245 return cmd_fd;
246 }
247
open_log_file(const char * mount_dir)248 int open_log_file(const char *mount_dir)
249 {
250 char file[255];
251 int fd;
252
253 snprintf(file, ARRAY_SIZE(file), "%s/.log", mount_dir);
254 fd = open(file, O_RDWR | O_CLOEXEC);
255 if (fd < 0)
256 perror("Can't open log file");
257 return fd;
258 }
259
open_blocks_written_file(const char * mount_dir)260 int open_blocks_written_file(const char *mount_dir)
261 {
262 char file[255];
263 int fd;
264
265 snprintf(file, ARRAY_SIZE(file),
266 "%s/%s", mount_dir, INCFS_BLOCKS_WRITTEN_FILENAME);
267 fd = open(file, O_RDONLY | O_CLOEXEC);
268
269 if (fd < 0)
270 perror("Can't open blocks_written file");
271 return fd;
272 }
273
wait_for_pending_reads(int fd,int timeout_ms,struct incfs_pending_read_info * prs,int prs_count)274 int wait_for_pending_reads(int fd, int timeout_ms,
275 struct incfs_pending_read_info *prs, int prs_count)
276 {
277 ssize_t read_res = 0;
278
279 if (timeout_ms > 0) {
280 int poll_res = 0;
281 struct pollfd pollfd = {
282 .fd = fd,
283 .events = POLLIN
284 };
285
286 poll_res = poll(&pollfd, 1, timeout_ms);
287 if (poll_res < 0)
288 return -errno;
289 if (poll_res == 0)
290 return 0;
291 if (!(pollfd.revents | POLLIN))
292 return 0;
293 }
294
295 read_res = read(fd, prs, prs_count * sizeof(*prs));
296 if (read_res < 0)
297 return -errno;
298
299 return read_res / sizeof(*prs);
300 }
301
wait_for_pending_reads2(int fd,int timeout_ms,struct incfs_pending_read_info2 * prs,int prs_count)302 int wait_for_pending_reads2(int fd, int timeout_ms,
303 struct incfs_pending_read_info2 *prs, int prs_count)
304 {
305 ssize_t read_res = 0;
306
307 if (timeout_ms > 0) {
308 int poll_res = 0;
309 struct pollfd pollfd = {
310 .fd = fd,
311 .events = POLLIN
312 };
313
314 poll_res = poll(&pollfd, 1, timeout_ms);
315 if (poll_res < 0)
316 return -errno;
317 if (poll_res == 0)
318 return 0;
319 if (!(pollfd.revents | POLLIN))
320 return 0;
321 }
322
323 read_res = read(fd, prs, prs_count * sizeof(*prs));
324 if (read_res < 0)
325 return -errno;
326
327 return read_res / sizeof(*prs);
328 }
329
concat_file_name(const char * dir,const char * file)330 char *concat_file_name(const char *dir, const char *file)
331 {
332 char full_name[FILENAME_MAX] = "";
333
334 if (snprintf(full_name, ARRAY_SIZE(full_name), "%s/%s", dir, file) < 0)
335 return NULL;
336 return strdup(full_name);
337 }
338
delete_dir_tree(const char * dir_path)339 int delete_dir_tree(const char *dir_path)
340 {
341 DIR *dir = NULL;
342 struct dirent *dp;
343 int result = 0;
344
345 dir = opendir(dir_path);
346 if (!dir) {
347 result = -errno;
348 goto out;
349 }
350
351 while ((dp = readdir(dir))) {
352 char *full_path;
353
354 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
355 continue;
356
357 full_path = concat_file_name(dir_path, dp->d_name);
358 if (dp->d_type == DT_DIR)
359 result = delete_dir_tree(full_path);
360 else
361 result = unlink(full_path);
362 free(full_path);
363 if (result)
364 goto out;
365 }
366
367 out:
368 if (dir)
369 closedir(dir);
370 if (!result)
371 rmdir(dir_path);
372 return result;
373 }
374
sha256(const char * data,size_t dsize,char * hash)375 void sha256(const char *data, size_t dsize, char *hash)
376 {
377 SHA256_CTX ctx;
378
379 SHA256_Init(&ctx);
380 SHA256_Update(&ctx, data, dsize);
381 SHA256_Final((unsigned char *)hash, &ctx);
382 }
383
md5(const char * data,size_t dsize,char * hash)384 void md5(const char *data, size_t dsize, char *hash)
385 {
386 MD5_CTX ctx;
387
388 MD5_Init(&ctx);
389 MD5_Update(&ctx, data, dsize);
390 MD5_Final((unsigned char *)hash, &ctx);
391 }
392