• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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