• 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 
mount_fs_opt(const char * mount_dir,const char * backing_dir,const char * opt,bool remount)84 int mount_fs_opt(const char *mount_dir, const char *backing_dir,
85 		 const char *opt, bool remount)
86 {
87 	static const char fs_name[] = INCFS_NAME;
88 	int result;
89 
90 	result = mount(backing_dir, mount_dir, fs_name,
91 		       remount ? MS_REMOUNT : 0, opt);
92 	if (result != 0)
93 		perror("Error mounting fs.");
94 	return result;
95 }
96 
97 struct hash_section {
98 	uint32_t algorithm;
99 	uint8_t log2_blocksize;
100 	uint32_t salt_size;
101 	/* no salt */
102 	uint32_t hash_size;
103 	uint8_t hash[SHA256_DIGEST_SIZE];
104 } __packed;
105 
106 struct signature_blob {
107 	uint32_t version;
108 	uint32_t hash_section_size;
109 	struct hash_section hash_section;
110 	uint32_t signing_section_size;
111 	uint8_t signing_section[];
112 } __packed;
113 
format_signature(void ** buf,const char * root_hash,const char * add_data)114 size_t format_signature(void **buf, const char *root_hash, const char *add_data)
115 {
116 	size_t size = sizeof(struct signature_blob) + strlen(add_data) + 1;
117 	struct signature_blob *sb = malloc(size);
118 
119 	if (!sb)
120 		return 0;
121 
122 	*sb = (struct signature_blob){
123 		.version = INCFS_SIGNATURE_VERSION,
124 		.hash_section_size = sizeof(struct hash_section),
125 		.hash_section =
126 			(struct hash_section){
127 				.algorithm = INCFS_HASH_TREE_SHA256,
128 				.log2_blocksize = 12,
129 				.salt_size = 0,
130 				.hash_size = SHA256_DIGEST_SIZE,
131 			},
132 		.signing_section_size = strlen(add_data) + 1,
133 	};
134 
135 	memcpy(sb->hash_section.hash, root_hash, SHA256_DIGEST_SIZE);
136 	memcpy((char *)sb->signing_section, add_data, strlen(add_data) + 1);
137 	*buf = sb;
138 	return size;
139 }
140 
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)141 int crypto_emit_file(int fd, const char *dir, const char *filename,
142 		     incfs_uuid_t *id_out, size_t size, const char *root_hash,
143 		     const char *add_data)
144 {
145 	int mode = __S_IFREG | 0555;
146 	void *signature;
147 	int error = 0;
148 
149 	struct incfs_new_file_args args = {
150 			.size = size,
151 			.mode = mode,
152 			.file_name = ptr_to_u64(filename),
153 			.directory_path = ptr_to_u64(dir),
154 			.file_attr = 0,
155 			.file_attr_len = 0
156 	};
157 
158 	args.signature_size = format_signature(&signature, root_hash, add_data);
159 	args.signature_info = ptr_to_u64(signature);
160 
161 	md5(filename, strlen(filename), (char *)args.file_id.bytes);
162 
163 	if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) {
164 		error = -errno;
165 		goto out;
166 	}
167 
168 	*id_out = args.file_id;
169 
170 out:
171 	free(signature);
172 	return error;
173 }
174 
emit_file(int fd,const char * dir,const char * filename,incfs_uuid_t * id_out,size_t size,const char * attr)175 int emit_file(int fd, const char *dir, const char *filename,
176 	      incfs_uuid_t *id_out, size_t size, const char *attr)
177 {
178 	int mode = __S_IFREG | 0555;
179 	struct incfs_new_file_args args = { .size = size,
180 					    .mode = mode,
181 					    .file_name = ptr_to_u64(filename),
182 					    .directory_path = ptr_to_u64(dir),
183 					    .signature_info = ptr_to_u64(NULL),
184 					    .signature_size = 0,
185 					    .file_attr = ptr_to_u64(attr),
186 					    .file_attr_len =
187 						    attr ? strlen(attr) : 0 };
188 
189 	md5(filename, strlen(filename), (char *)args.file_id.bytes);
190 
191 	if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0)
192 		return -errno;
193 
194 	*id_out = args.file_id;
195 	return 0;
196 }
197 
get_file_bmap(int cmd_fd,int ino,unsigned char * buf,int buf_size)198 int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size)
199 {
200 	return 0;
201 }
202 
get_file_signature(int fd,unsigned char * buf,int buf_size)203 int get_file_signature(int fd, unsigned char *buf, int buf_size)
204 {
205 	struct incfs_get_file_sig_args args = {
206 		.file_signature = ptr_to_u64(buf),
207 		.file_signature_buf_size = buf_size
208 	};
209 
210 	if (ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &args) == 0)
211 		return args.file_signature_len_out;
212 	return -errno;
213 }
214 
get_file_size(const char * name)215 loff_t get_file_size(const char *name)
216 {
217 	struct stat st;
218 
219 	if (stat(name, &st) == 0)
220 		return st.st_size;
221 	return -ENOENT;
222 }
223 
open_commands_file(const char * mount_dir)224 int open_commands_file(const char *mount_dir)
225 {
226 	char cmd_file[255];
227 	int cmd_fd;
228 
229 	snprintf(cmd_file, ARRAY_SIZE(cmd_file),
230 			"%s/%s", mount_dir, INCFS_PENDING_READS_FILENAME);
231 	cmd_fd = open(cmd_file, O_RDONLY | O_CLOEXEC);
232 
233 	if (cmd_fd < 0)
234 		perror("Can't open commands file");
235 	return cmd_fd;
236 }
237 
open_log_file(const char * mount_dir)238 int open_log_file(const char *mount_dir)
239 {
240 	char file[255];
241 	int fd;
242 
243 	snprintf(file, ARRAY_SIZE(file), "%s/.log", mount_dir);
244 	fd = open(file, O_RDWR | O_CLOEXEC);
245 	if (fd < 0)
246 		perror("Can't open log file");
247 	return fd;
248 }
249 
open_blocks_written_file(const char * mount_dir)250 int open_blocks_written_file(const char *mount_dir)
251 {
252 	char file[255];
253 	int fd;
254 
255 	snprintf(file, ARRAY_SIZE(file),
256 			"%s/%s", mount_dir, INCFS_BLOCKS_WRITTEN_FILENAME);
257 	fd = open(file, O_RDONLY | O_CLOEXEC);
258 
259 	if (fd < 0)
260 		perror("Can't open blocks_written file");
261 	return fd;
262 }
263 
wait_for_pending_reads(int fd,int timeout_ms,struct incfs_pending_read_info * prs,int prs_count)264 int wait_for_pending_reads(int fd, int timeout_ms,
265 	struct incfs_pending_read_info *prs, int prs_count)
266 {
267 	ssize_t read_res = 0;
268 
269 	if (timeout_ms > 0) {
270 		int poll_res = 0;
271 		struct pollfd pollfd = {
272 			.fd = fd,
273 			.events = POLLIN
274 		};
275 
276 		poll_res = poll(&pollfd, 1, timeout_ms);
277 		if (poll_res < 0)
278 			return -errno;
279 		if (poll_res == 0)
280 			return 0;
281 		if (!(pollfd.revents | POLLIN))
282 			return 0;
283 	}
284 
285 	read_res = read(fd, prs, prs_count * sizeof(*prs));
286 	if (read_res < 0)
287 		return -errno;
288 
289 	return read_res / sizeof(*prs);
290 }
291 
wait_for_pending_reads2(int fd,int timeout_ms,struct incfs_pending_read_info2 * prs,int prs_count)292 int wait_for_pending_reads2(int fd, int timeout_ms,
293 	struct incfs_pending_read_info2 *prs, int prs_count)
294 {
295 	ssize_t read_res = 0;
296 
297 	if (timeout_ms > 0) {
298 		int poll_res = 0;
299 		struct pollfd pollfd = {
300 			.fd = fd,
301 			.events = POLLIN
302 		};
303 
304 		poll_res = poll(&pollfd, 1, timeout_ms);
305 		if (poll_res < 0)
306 			return -errno;
307 		if (poll_res == 0)
308 			return 0;
309 		if (!(pollfd.revents | POLLIN))
310 			return 0;
311 	}
312 
313 	read_res = read(fd, prs, prs_count * sizeof(*prs));
314 	if (read_res < 0)
315 		return -errno;
316 
317 	return read_res / sizeof(*prs);
318 }
319 
concat_file_name(const char * dir,const char * file)320 char *concat_file_name(const char *dir, const char *file)
321 {
322 	char full_name[FILENAME_MAX] = "";
323 
324 	if (snprintf(full_name, ARRAY_SIZE(full_name), "%s/%s", dir, file) < 0)
325 		return NULL;
326 	return strdup(full_name);
327 }
328 
delete_dir_tree(const char * dir_path)329 int delete_dir_tree(const char *dir_path)
330 {
331 	DIR *dir = NULL;
332 	struct dirent *dp;
333 	int result = 0;
334 
335 	dir = opendir(dir_path);
336 	if (!dir) {
337 		result = -errno;
338 		goto out;
339 	}
340 
341 	while ((dp = readdir(dir))) {
342 		char *full_path;
343 
344 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
345 			continue;
346 
347 		full_path = concat_file_name(dir_path, dp->d_name);
348 		if (dp->d_type == DT_DIR)
349 			result = delete_dir_tree(full_path);
350 		else
351 			result = unlink(full_path);
352 		free(full_path);
353 		if (result)
354 			goto out;
355 	}
356 
357 out:
358 	if (dir)
359 		closedir(dir);
360 	if (!result)
361 		rmdir(dir_path);
362 	return result;
363 }
364 
sha256(const char * data,size_t dsize,char * hash)365 void sha256(const char *data, size_t dsize, char *hash)
366 {
367 	SHA256_CTX ctx;
368 
369 	SHA256_Init(&ctx);
370 	SHA256_Update(&ctx, data, dsize);
371 	SHA256_Final((unsigned char *)hash, &ctx);
372 }
373 
md5(const char * data,size_t dsize,char * hash)374 void md5(const char *data, size_t dsize, char *hash)
375 {
376 	MD5_CTX ctx;
377 
378 	MD5_Init(&ctx);
379 	MD5_Update(&ctx, data, dsize);
380 	MD5_Final((unsigned char *)hash, &ctx);
381 }
382