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
mount_fs(const char * mount_dir,const char * backing_dir,int read_timeout_ms)28 int mount_fs(const char *mount_dir, const char *backing_dir,
29 int read_timeout_ms)
30 {
31 static const char fs_name[] = INCFS_NAME;
32 char mount_options[512];
33 int result;
34
35 snprintf(mount_options, ARRAY_SIZE(mount_options),
36 "read_timeout_ms=%u",
37 read_timeout_ms);
38
39 result = mount(backing_dir, mount_dir, fs_name, 0, mount_options);
40 if (result != 0)
41 perror("Error mounting fs.");
42 return result;
43 }
44
mount_fs_opt(const char * mount_dir,const char * backing_dir,const char * opt,bool remount)45 int mount_fs_opt(const char *mount_dir, const char *backing_dir,
46 const char *opt, bool remount)
47 {
48 static const char fs_name[] = INCFS_NAME;
49 int result;
50
51 result = mount(backing_dir, mount_dir, fs_name,
52 remount ? MS_REMOUNT : 0, opt);
53 if (result != 0)
54 perror("Error mounting fs.");
55 return result;
56 }
57
58 struct hash_section {
59 uint32_t algorithm;
60 uint8_t log2_blocksize;
61 uint32_t salt_size;
62 /* no salt */
63 uint32_t hash_size;
64 uint8_t hash[SHA256_DIGEST_SIZE];
65 } __packed;
66
67 struct signature_blob {
68 uint32_t version;
69 uint32_t hash_section_size;
70 struct hash_section hash_section;
71 uint32_t signing_section_size;
72 uint8_t signing_section[];
73 } __packed;
74
format_signature(void ** buf,const char * root_hash,const char * add_data)75 size_t format_signature(void **buf, const char *root_hash, const char *add_data)
76 {
77 size_t size = sizeof(struct signature_blob) + strlen(add_data) + 1;
78 struct signature_blob *sb = malloc(size);
79
80 *sb = (struct signature_blob){
81 .version = INCFS_SIGNATURE_VERSION,
82 .hash_section_size = sizeof(struct hash_section),
83 .hash_section =
84 (struct hash_section){
85 .algorithm = INCFS_HASH_TREE_SHA256,
86 .log2_blocksize = 12,
87 .salt_size = 0,
88 .hash_size = SHA256_DIGEST_SIZE,
89 },
90 .signing_section_size = sizeof(uint32_t) + strlen(add_data) + 1,
91 };
92
93 memcpy(sb->hash_section.hash, root_hash, SHA256_DIGEST_SIZE);
94 memcpy((char *)sb->signing_section, add_data, strlen(add_data) + 1);
95 *buf = sb;
96 return size;
97 }
98
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)99 int crypto_emit_file(int fd, const char *dir, const char *filename,
100 incfs_uuid_t *id_out, size_t size, const char *root_hash,
101 const char *add_data)
102 {
103 int mode = __S_IFREG | 0555;
104 void *signature;
105 int error = 0;
106
107 struct incfs_new_file_args args = {
108 .size = size,
109 .mode = mode,
110 .file_name = ptr_to_u64(filename),
111 .directory_path = ptr_to_u64(dir),
112 .file_attr = 0,
113 .file_attr_len = 0
114 };
115
116 args.signature_size = format_signature(&signature, root_hash, add_data);
117 args.signature_info = ptr_to_u64(signature);
118
119 md5(filename, strlen(filename), (char *)args.file_id.bytes);
120
121 if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) {
122 error = -errno;
123 goto out;
124 }
125
126 *id_out = args.file_id;
127
128 out:
129 free(signature);
130 return error;
131 }
132
emit_file(int fd,const char * dir,const char * filename,incfs_uuid_t * id_out,size_t size,const char * attr)133 int emit_file(int fd, const char *dir, const char *filename,
134 incfs_uuid_t *id_out, size_t size, const char *attr)
135 {
136 int mode = __S_IFREG | 0555;
137 struct incfs_new_file_args args = { .size = size,
138 .mode = mode,
139 .file_name = ptr_to_u64(filename),
140 .directory_path = ptr_to_u64(dir),
141 .signature_info = ptr_to_u64(NULL),
142 .signature_size = 0,
143 .file_attr = ptr_to_u64(attr),
144 .file_attr_len =
145 attr ? strlen(attr) : 0 };
146
147 md5(filename, strlen(filename), (char *)args.file_id.bytes);
148
149 if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0)
150 return -errno;
151
152 *id_out = args.file_id;
153 return 0;
154 }
155
get_file_bmap(int cmd_fd,int ino,unsigned char * buf,int buf_size)156 int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size)
157 {
158 return 0;
159 }
160
get_file_signature(int fd,unsigned char * buf,int buf_size)161 int get_file_signature(int fd, unsigned char *buf, int buf_size)
162 {
163 struct incfs_get_file_sig_args args = {
164 .file_signature = ptr_to_u64(buf),
165 .file_signature_buf_size = buf_size
166 };
167
168 if (ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &args) == 0)
169 return args.file_signature_len_out;
170 return -errno;
171 }
172
get_file_size(const char * name)173 loff_t get_file_size(const char *name)
174 {
175 struct stat st;
176
177 if (stat(name, &st) == 0)
178 return st.st_size;
179 return -ENOENT;
180 }
181
open_commands_file(const char * mount_dir)182 int open_commands_file(const char *mount_dir)
183 {
184 char cmd_file[255];
185 int cmd_fd;
186
187 snprintf(cmd_file, ARRAY_SIZE(cmd_file),
188 "%s/%s", mount_dir, INCFS_PENDING_READS_FILENAME);
189 cmd_fd = open(cmd_file, O_RDONLY | O_CLOEXEC);
190
191 if (cmd_fd < 0)
192 perror("Can't open commands file");
193 return cmd_fd;
194 }
195
open_log_file(const char * mount_dir)196 int open_log_file(const char *mount_dir)
197 {
198 char cmd_file[255];
199 int cmd_fd;
200
201 snprintf(cmd_file, ARRAY_SIZE(cmd_file), "%s/.log", mount_dir);
202 cmd_fd = open(cmd_file, O_RDWR | O_CLOEXEC);
203 if (cmd_fd < 0)
204 perror("Can't open log file");
205 return cmd_fd;
206 }
207
wait_for_pending_reads(int fd,int timeout_ms,struct incfs_pending_read_info * prs,int prs_count)208 int wait_for_pending_reads(int fd, int timeout_ms,
209 struct incfs_pending_read_info *prs, int prs_count)
210 {
211 ssize_t read_res = 0;
212
213 if (timeout_ms > 0) {
214 int poll_res = 0;
215 struct pollfd pollfd = {
216 .fd = fd,
217 .events = POLLIN
218 };
219
220 poll_res = poll(&pollfd, 1, timeout_ms);
221 if (poll_res < 0)
222 return -errno;
223 if (poll_res == 0)
224 return 0;
225 if (!(pollfd.revents | POLLIN))
226 return 0;
227 }
228
229 read_res = read(fd, prs, prs_count * sizeof(*prs));
230 if (read_res < 0)
231 return -errno;
232
233 return read_res / sizeof(*prs);
234 }
235
concat_file_name(const char * dir,char * file)236 char *concat_file_name(const char *dir, char *file)
237 {
238 char full_name[FILENAME_MAX] = "";
239
240 if (snprintf(full_name, ARRAY_SIZE(full_name), "%s/%s", dir, file) < 0)
241 return NULL;
242 return strdup(full_name);
243 }
244
delete_dir_tree(const char * dir_path)245 int delete_dir_tree(const char *dir_path)
246 {
247 DIR *dir = NULL;
248 struct dirent *dp;
249 int result = 0;
250
251 dir = opendir(dir_path);
252 if (!dir) {
253 result = -errno;
254 goto out;
255 }
256
257 while ((dp = readdir(dir))) {
258 char *full_path;
259
260 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
261 continue;
262
263 full_path = concat_file_name(dir_path, dp->d_name);
264 if (dp->d_type == DT_DIR)
265 result = delete_dir_tree(full_path);
266 else
267 result = unlink(full_path);
268 free(full_path);
269 if (result)
270 goto out;
271 }
272
273 out:
274 if (dir)
275 closedir(dir);
276 if (!result)
277 rmdir(dir_path);
278 return result;
279 }
280
sha256(const char * data,size_t dsize,char * hash)281 void sha256(const char *data, size_t dsize, char *hash)
282 {
283 SHA256_CTX ctx;
284
285 SHA256_Init(&ctx);
286 SHA256_Update(&ctx, data, dsize);
287 SHA256_Final((unsigned char *)hash, &ctx);
288 }
289
md5(const char * data,size_t dsize,char * hash)290 void md5(const char *data, size_t dsize, char *hash)
291 {
292 MD5_CTX ctx;
293
294 MD5_Init(&ctx);
295 MD5_Update(&ctx, data, dsize);
296 MD5_Final((unsigned char *)hash, &ctx);
297 }
298