• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2018 Google LLC
4  */
5 #include <stdio.h>
6 #include <fcntl.h>
7 #include <dirent.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <sys/ioctl.h>
13 #include <sys/mount.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <poll.h>
17 #include <openssl/bio.h>
18 #include <openssl/err.h>
19 #include <openssl/pem.h>
20 #include <openssl/pkcs7.h>
21 #include <openssl/sha.h>
22 #include <openssl/md5.h>
23 
24 #include "utils.h"
25 
mount_fs(char * mount_dir,char * backing_dir,int read_timeout_ms)26 int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms)
27 {
28 	static const char fs_name[] = INCFS_NAME;
29 	char mount_options[512];
30 	int result;
31 
32 	snprintf(mount_options, ARRAY_SIZE(mount_options),
33 		 "read_timeout_ms=%u",
34 		  read_timeout_ms);
35 
36 	result = mount(backing_dir, mount_dir, fs_name, 0, mount_options);
37 	if (result != 0)
38 		perror("Error mounting fs.");
39 	return result;
40 }
41 
mount_fs_opt(char * mount_dir,char * backing_dir,char * opt)42 int mount_fs_opt(char *mount_dir, char *backing_dir, char *opt)
43 {
44 	static const char fs_name[] = INCFS_NAME;
45 	int result;
46 
47 	result = mount(backing_dir, mount_dir, fs_name, 0, opt);
48 	if (result != 0)
49 		perror("Error mounting fs.");
50 	return result;
51 }
52 
unlink_node(int fd,int parent_ino,char * filename)53 int unlink_node(int fd, int parent_ino, char *filename)
54 {
55 	return 0;
56 }
57 
58 
deserialize_private_key(const char * pem_key)59 static EVP_PKEY *deserialize_private_key(const char *pem_key)
60 {
61 	BIO *bio = NULL;
62 	EVP_PKEY *pkey = NULL;
63 	int len = strlen(pem_key);
64 
65 	bio = BIO_new_mem_buf(pem_key, len);
66 	if (!bio)
67 		return NULL;
68 
69 	pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
70 	BIO_free(bio);
71 	return pkey;
72 }
73 
deserialize_cert(const char * pem_cert)74 static X509 *deserialize_cert(const char *pem_cert)
75 {
76 	BIO *bio = NULL;
77 	X509 *cert = NULL;
78 	int len = strlen(pem_cert);
79 
80 	bio = BIO_new_mem_buf(pem_cert, len);
81 	if (!bio)
82 		return NULL;
83 
84 	cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
85 	BIO_free(bio);
86 	return cert;
87 }
88 
sign_pkcs7(const void * data_to_sign,size_t data_size,char * pkey_pem,char * cert_pem,void ** sig_ret,size_t * sig_size_ret)89 bool sign_pkcs7(const void *data_to_sign, size_t data_size,
90 		       char *pkey_pem, char *cert_pem,
91 		       void **sig_ret, size_t *sig_size_ret)
92 {
93 	/*
94 	 * PKCS#7 signing flags:
95 	 *
96 	 * - PKCS7_BINARY	signing binary data, so skip MIME translation
97 	 *
98 	 * - PKCS7_NOATTR	omit extra authenticated attributes, such as
99 	 *			SMIMECapabilities
100 	 *
101 	 * - PKCS7_PARTIAL	PKCS7_sign() creates a handle only, then
102 	 *			PKCS7_sign_add_signer() can add a signer later.
103 	 *			This is necessary to change the message digest
104 	 *			algorithm from the default of SHA-1.  Requires
105 	 *			OpenSSL 1.0.0 or later.
106 	 */
107 	int pkcs7_flags = PKCS7_BINARY | PKCS7_NOATTR | PKCS7_PARTIAL;
108 	void *sig;
109 	size_t sig_size;
110 	BIO *bio = NULL;
111 	PKCS7 *p7 = NULL;
112 	EVP_PKEY *pkey = NULL;
113 	X509 *cert = NULL;
114 	bool ok = false;
115 
116 	const EVP_MD *md = EVP_sha256();
117 
118 	pkey = deserialize_private_key(pkey_pem);
119 	if (!pkey) {
120 		printf("deserialize_private_key failed\n");
121 		goto out;
122 	}
123 
124 	cert = deserialize_cert(cert_pem);
125 	if (!cert) {
126 		printf("deserialize_cert failed\n");
127 		goto out;
128 	}
129 
130 	bio = BIO_new_mem_buf(data_to_sign, data_size);
131 	if (!bio)
132 		goto out;
133 
134 	p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags);
135 	if (!p7) {
136 		printf("failed to initialize PKCS#7 signature object\n");
137 		goto out;
138 	}
139 
140 	if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) {
141 		printf("failed to add signer to PKCS#7 signature object\n");
142 		goto out;
143 	}
144 
145 	if (PKCS7_final(p7, bio, pkcs7_flags) != 1) {
146 		printf("failed to finalize PKCS#7 signature\n");
147 		goto out;
148 	}
149 
150 	BIO_free(bio);
151 	bio = BIO_new(BIO_s_mem());
152 	if (!bio) {
153 		printf("out of memory\n");
154 		goto out;
155 	}
156 
157 	if (i2d_PKCS7_bio(bio, p7) != 1) {
158 		printf("failed to DER-encode PKCS#7 signature object\n");
159 		goto out;
160 	}
161 
162 	sig_size = BIO_get_mem_data(bio, &sig);
163 	*sig_ret = malloc(sig_size);
164 	memcpy(*sig_ret, sig, sig_size);
165 	*sig_size_ret = sig_size;
166 	ok = true;
167 out:
168 	PKCS7_free(p7);
169 	BIO_free(bio);
170 	return ok;
171 }
172 
crypto_emit_file(int fd,char * dir,char * filename,incfs_uuid_t * id_out,size_t size,const char * root_hash,char * sig,size_t sig_size,char * add_data)173 int crypto_emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out,
174 	size_t size, const char *root_hash, char *sig, size_t sig_size,
175 	char *add_data)
176 {
177 	int mode = __S_IFREG | 0555;
178 	struct incfs_file_signature_info sig_info = {
179 		.hash_tree_alg = root_hash
180 					? INCFS_HASH_TREE_SHA256
181 					: 0,
182 		.root_hash = ptr_to_u64(root_hash),
183 		.additional_data = ptr_to_u64(add_data),
184 		.additional_data_size = strlen(add_data),
185 		.signature =  ptr_to_u64(sig),
186 		.signature_size = sig_size,
187 	};
188 
189 	struct incfs_new_file_args args = {
190 			.size = size,
191 			.mode = mode,
192 			.file_name = ptr_to_u64(filename),
193 			.directory_path = ptr_to_u64(dir),
194 			.signature_info = ptr_to_u64(&sig_info),
195 			.file_attr = 0,
196 			.file_attr_len = 0
197 	};
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 
208 
emit_file(int fd,char * dir,char * filename,incfs_uuid_t * id_out,size_t size,char * attr)209 int emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out,
210 		size_t size, char *attr)
211 {
212 	int mode = __S_IFREG | 0555;
213 	struct incfs_file_signature_info sig_info = {
214 		.hash_tree_alg = 0,
215 		.root_hash = ptr_to_u64(NULL)
216 	};
217 	struct incfs_new_file_args args = {
218 			.size = size,
219 			.mode = mode,
220 			.file_name = ptr_to_u64(filename),
221 			.directory_path = ptr_to_u64(dir),
222 			.signature_info = ptr_to_u64(&sig_info),
223 			.file_attr = ptr_to_u64(attr),
224 			.file_attr_len = attr ? strlen(attr) : 0
225 	};
226 
227 	md5(filename, strlen(filename), (char *)args.file_id.bytes);
228 
229 	if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0)
230 		return -errno;
231 
232 	*id_out = args.file_id;
233 	return 0;
234 }
235 
get_file_bmap(int cmd_fd,int ino,unsigned char * buf,int buf_size)236 int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size)
237 {
238 	return 0;
239 }
240 
get_file_signature(int fd,unsigned char * buf,int buf_size)241 int get_file_signature(int fd, unsigned char *buf, int buf_size)
242 {
243 	struct incfs_get_file_sig_args args = {
244 		.file_signature = ptr_to_u64(buf),
245 		.file_signature_buf_size = buf_size
246 	};
247 
248 	if (ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &args) == 0)
249 		return args.file_signature_len_out;
250 	return -errno;
251 }
252 
get_file_size(char * name)253 loff_t get_file_size(char *name)
254 {
255 	struct stat st;
256 
257 	if (stat(name, &st) == 0)
258 		return st.st_size;
259 	return -ENOENT;
260 }
261 
open_commands_file(char * mount_dir)262 int open_commands_file(char *mount_dir)
263 {
264 	char cmd_file[255];
265 	int cmd_fd;
266 
267 	snprintf(cmd_file, ARRAY_SIZE(cmd_file),
268 			"%s/%s", mount_dir, INCFS_PENDING_READS_FILENAME);
269 	cmd_fd = open(cmd_file, O_RDONLY);
270 
271 	if (cmd_fd < 0)
272 		perror("Can't open commands file");
273 	return cmd_fd;
274 }
275 
open_log_file(char * mount_dir)276 int open_log_file(char *mount_dir)
277 {
278 	char cmd_file[255];
279 	int cmd_fd;
280 
281 	snprintf(cmd_file, ARRAY_SIZE(cmd_file), "%s/.log", mount_dir);
282 	cmd_fd = open(cmd_file, O_RDWR);
283 	if (cmd_fd < 0)
284 		perror("Can't open log file");
285 	return cmd_fd;
286 }
287 
wait_for_pending_reads(int fd,int timeout_ms,struct incfs_pending_read_info * prs,int prs_count)288 int wait_for_pending_reads(int fd, int timeout_ms,
289 	struct incfs_pending_read_info *prs, int prs_count)
290 {
291 	ssize_t read_res = 0;
292 
293 	if (timeout_ms > 0) {
294 		int poll_res = 0;
295 		struct pollfd pollfd = {
296 			.fd = fd,
297 			.events = POLLIN
298 		};
299 
300 		poll_res = poll(&pollfd, 1, timeout_ms);
301 		if (poll_res < 0)
302 			return -errno;
303 		if (poll_res == 0)
304 			return 0;
305 		if (!(pollfd.revents | POLLIN))
306 			return 0;
307 	}
308 
309 	read_res = read(fd, prs, prs_count * sizeof(*prs));
310 	if (read_res < 0)
311 		return -errno;
312 
313 	return read_res / sizeof(*prs);
314 }
315 
concat_file_name(const char * dir,char * file)316 char *concat_file_name(const char *dir, char *file)
317 {
318 	char full_name[FILENAME_MAX] = "";
319 
320 	if (snprintf(full_name, ARRAY_SIZE(full_name), "%s/%s", dir, file) < 0)
321 		return NULL;
322 	return strdup(full_name);
323 }
324 
delete_dir_tree(const char * dir_path)325 int delete_dir_tree(const char *dir_path)
326 {
327 	DIR *dir = NULL;
328 	struct dirent *dp;
329 	int result = 0;
330 
331 	dir = opendir(dir_path);
332 	if (!dir) {
333 		result = -errno;
334 		goto out;
335 	}
336 
337 	while ((dp = readdir(dir))) {
338 		char *full_path;
339 
340 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
341 			continue;
342 
343 		full_path = concat_file_name(dir_path, dp->d_name);
344 		if (dp->d_type == DT_DIR)
345 			result = delete_dir_tree(full_path);
346 		else
347 			result = unlink(full_path);
348 		free(full_path);
349 		if (result)
350 			goto out;
351 	}
352 
353 out:
354 	if (dir)
355 		closedir(dir);
356 	if (!result)
357 		rmdir(dir_path);
358 	return result;
359 }
360 
sha256(char * data,size_t dsize,char * hash)361 void sha256(char *data, size_t dsize, char *hash)
362 {
363 	SHA256_CTX ctx;
364 
365 	SHA256_Init(&ctx);
366 	SHA256_Update(&ctx, data, dsize);
367 	SHA256_Final((unsigned char *)hash, &ctx);
368 }
369 
md5(char * data,size_t dsize,char * hash)370 void md5(char *data, size_t dsize, char *hash)
371 {
372 	MD5_CTX ctx;
373 
374 	MD5_Init(&ctx);
375 	MD5_Update(&ctx, data, dsize);
376 	MD5_Final((unsigned char *)hash, &ctx);
377 }
378