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