]> git.proxmox.com Git - mirror_lxcfs.git/blob - src/utils.c
Add support for fuse3
[mirror_lxcfs.git] / src / utils.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #endif
6
7 #include "config.h"
8
9 #ifdef HAVE_FUSE3
10 #ifndef FUSE_USE_VERSION
11 #define FUSE_USE_VERSION 30
12 #endif
13 #else
14 #ifndef FUSE_USE_VERSION
15 #define FUSE_USE_VERSION 26
16 #endif
17 #endif
18
19 #define _FILE_OFFSET_BITS 64
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <fuse.h>
25 #include <inttypes.h>
26 #include <sched.h>
27 #include <stdarg.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/epoll.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <unistd.h>
38
39 #include "bindings.h"
40 #include "macro.h"
41 #include "memory_utils.h"
42 #include "utils.h"
43
44 /*
45 * append the given formatted string to *src.
46 * src: a pointer to a char* in which to append the formatted string.
47 * sz: the number of characters printed so far, minus trailing \0.
48 * asz: the allocated size so far
49 * format: string format. See printf for details.
50 * ...: varargs. See printf for details.
51 */
52 /*
53 * append the given formatted string to *src.
54 * src: a pointer to a char* in which to append the formatted string.
55 * sz: the number of characters printed so far, minus trailing \0.
56 * asz: the allocated size so far
57 * format: string format. See printf for details.
58 * ...: varargs. See printf for details.
59 */
60 char *must_strcat(char **src, size_t *sz, size_t *asz, const char *format, ...)
61 {
62 char tmp[BUF_RESERVE_SIZE];
63 va_list args;
64 int tmplen;
65
66 va_start (args, format);
67 tmplen = vsnprintf(tmp, BUF_RESERVE_SIZE, format, args);
68 va_end(args);
69
70 if (!*src || tmplen + *sz + 1 >= *asz) {
71 char *str;
72 do {
73 str = realloc(*src, *asz + BUF_RESERVE_SIZE);
74 } while (!str);
75 *src = str;
76 *asz += BUF_RESERVE_SIZE;
77 }
78 memcpy((*src) +*sz , tmp, tmplen+1); /* include the \0 */
79 *sz += tmplen;
80
81 return *src;
82 }
83
84 /**
85 * in_same_namespace - Check whether two processes are in the same namespace.
86 * @pid1 - PID of the first process.
87 * @pid2 - PID of the second process.
88 * @ns - Name of the namespace to check. Must correspond to one of the names
89 * for the namespaces as shown in /proc/<pid/ns/
90 *
91 * If the two processes are not in the same namespace returns an fd to the
92 * namespace of the second process identified by @pid2. If the two processes are
93 * in the same namespace returns -EINVAL, -1 if an error occurred.
94 */
95 static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
96 {
97 __do_close int ns_fd1 = -1, ns_fd2 = -1;
98 int ret = -1;
99 struct stat ns_st1, ns_st2;
100
101 ns_fd1 = preserve_ns(pid1, ns);
102 if (ns_fd1 < 0) {
103 /* The kernel does not support this namespace. This is not an
104 * error.
105 */
106 if (errno == ENOENT)
107 return -EINVAL;
108
109 return -1;
110 }
111
112 ns_fd2 = preserve_ns(pid2, ns);
113 if (ns_fd2 < 0)
114 return -1;
115
116 ret = fstat(ns_fd1, &ns_st1);
117 if (ret < 0)
118 return -1;
119
120 ret = fstat(ns_fd2, &ns_st2);
121 if (ret < 0)
122 return -1;
123
124 /* processes are in the same namespace */
125 if ((ns_st1.st_dev == ns_st2.st_dev) && (ns_st1.st_ino == ns_st2.st_ino))
126 return -EINVAL;
127
128 /* processes are in different namespaces */
129 return move_fd(ns_fd2);
130 }
131
132 bool is_shared_pidns(pid_t pid)
133 {
134 __do_close int fd = -EBADF;
135
136 if (pid != 1)
137 return false;
138
139 fd = in_same_namespace(pid, getpid(), "pid");
140 if (fd == EINVAL)
141 return true;
142
143 return false;
144 }
145
146 int preserve_ns(const int pid, const char *ns)
147 {
148 int ret;
149 /* 5 /proc + 21 /int_as_str + 3 /ns + 20 /NS_NAME + 1 \0 */
150 #define __NS_PATH_LEN 50
151 char path[__NS_PATH_LEN];
152
153 /* This way we can use this function to also check whether namespaces
154 * are supported by the kernel by passing in the NULL or the empty
155 * string.
156 */
157 ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid,
158 !ns || strcmp(ns, "") == 0 ? "" : "/",
159 !ns || strcmp(ns, "") == 0 ? "" : ns);
160 if (ret < 0 || (size_t)ret >= __NS_PATH_LEN) {
161 errno = EFBIG;
162 return -1;
163 }
164
165 return open(path, O_RDONLY | O_CLOEXEC);
166 }
167
168 void do_release_file_info(struct fuse_file_info *fi)
169 {
170 struct file_info *f;
171
172 f = INTTYPE_TO_PTR(fi->fh);
173 if (!f)
174 return;
175
176 fi->fh = 0;
177
178 free_disarm(f->controller);
179 free_disarm(f->cgroup);
180 free_disarm(f->file);
181 free_disarm(f->buf);
182 free_disarm(f);
183 }
184
185 #define POLLIN_SET ( EPOLLIN | EPOLLHUP | EPOLLRDHUP )
186
187 bool wait_for_sock(int sock, int timeout)
188 {
189 __do_close int epfd = -EBADF;
190 struct epoll_event ev;
191 int ret, now, starttime, deltatime;
192
193 if ((starttime = time(NULL)) < 0)
194 return false;
195
196 epfd = epoll_create(1);
197 if (epfd < 0)
198 return log_error(false, "%m - Failed to create epoll socket");
199
200 ev.events = POLLIN_SET;
201 ev.data.fd = sock;
202 if (epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev) < 0)
203 return log_error(false, "Failed adding socket to epoll: %m");
204
205 again:
206 if ((now = time(NULL)) < 0)
207 return false;
208
209 deltatime = (starttime + timeout) - now;
210 if (deltatime < 0)
211 return false;
212
213 ret = epoll_wait(epfd, &ev, 1, 1000*deltatime + 1);
214 if (ret < 0 && errno == EINTR)
215 goto again;
216
217 if (ret <= 0)
218 return false;
219
220 return true;
221 }
222
223 bool recv_creds(int sock, struct ucred *cred, char *v)
224 {
225 struct msghdr msg = {};
226 struct iovec iov;
227 struct cmsghdr *cmsg;
228 ssize_t ret;
229 char cmsgbuf[CMSG_SPACE(sizeof(*cred))] = {};
230 char buf = '1';
231 int optval = 1;
232
233 msg.msg_name = NULL;
234 msg.msg_namelen = 0;
235 msg.msg_control = cmsgbuf;
236 msg.msg_controllen = sizeof(cmsgbuf);
237
238 iov.iov_base = &buf;
239 iov.iov_len = sizeof(buf);
240 msg.msg_iov = &iov;
241 msg.msg_iovlen = 1;
242
243 *v = buf;
244
245 ret = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval));
246 if (ret < 0)
247 return log_error(false, "Failed to set passcred: %s\n", strerror(errno));
248
249 ret = write_nointr(sock, &buf, sizeof(buf));
250 if (ret != sizeof(buf))
251 return log_error(false, "Failed to start write on scm fd: %s\n", strerror(errno));
252
253 if (!wait_for_sock(sock, 2))
254 return log_error(false, "Timed out waiting for scm_cred: %s\n", strerror(errno));
255
256 ret = recvmsg(sock, &msg, MSG_DONTWAIT);
257 if (ret < 0)
258 return log_error(false, "Failed to receive scm_cred: %s\n", strerror(errno));
259
260 cmsg = CMSG_FIRSTHDR(&msg);
261
262 if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(*cred)) &&
263 cmsg->cmsg_level == SOL_SOCKET &&
264 cmsg->cmsg_type == SCM_CREDENTIALS) {
265 memcpy(cred, CMSG_DATA(cmsg), sizeof(*cred));
266 }
267 *v = buf;
268
269 return true;
270 }
271
272 static int msgrecv(int sockfd, void *buf, size_t len)
273 {
274 if (!wait_for_sock(sockfd, 2))
275 return -1;
276
277 return recv(sockfd, buf, len, MSG_DONTWAIT);
278 }
279
280 int send_creds(int sock, struct ucred *cred, char v, bool pingfirst)
281 {
282 struct msghdr msg = { 0 };
283 struct iovec iov;
284 struct cmsghdr *cmsg;
285 char cmsgbuf[CMSG_SPACE(sizeof(*cred))];
286 char buf[1];
287 buf[0] = 'p';
288
289 if (pingfirst && msgrecv(sock, buf, 1) != 1)
290 return log_error(SEND_CREDS_FAIL, "%s - Failed getting reply from server over socketpair: %d",
291 strerror(errno), SEND_CREDS_FAIL);
292
293 msg.msg_control = cmsgbuf;
294 msg.msg_controllen = sizeof(cmsgbuf);
295
296 cmsg = CMSG_FIRSTHDR(&msg);
297 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
298 cmsg->cmsg_level = SOL_SOCKET;
299 cmsg->cmsg_type = SCM_CREDENTIALS;
300 memcpy(CMSG_DATA(cmsg), cred, sizeof(*cred));
301
302 msg.msg_name = NULL;
303 msg.msg_namelen = 0;
304
305 buf[0] = v;
306 iov.iov_base = buf;
307 iov.iov_len = sizeof(buf);
308 msg.msg_iov = &iov;
309 msg.msg_iovlen = 1;
310
311 if (sendmsg(sock, &msg, 0) < 0) {
312 if (errno == 3)
313 return log_error(SEND_CREDS_NOTSK, "%s - Failed at sendmsg: %d", strerror(errno), SEND_CREDS_NOTSK);
314
315 return log_error(SEND_CREDS_FAIL, "%s - Failed at sendmsg: %d", strerror(errno), SEND_CREDS_FAIL);
316 }
317
318 return SEND_CREDS_OK;
319 }
320
321 int read_file_fuse(const char *path, char *buf, size_t size, struct file_info *d)
322 {
323 __do_free char *line = NULL;
324 __do_fclose FILE *f = NULL;
325 size_t linelen = 0, total_len = 0;
326 char *cache = d->buf;
327 size_t cache_size = d->buflen;
328
329 f = fopen(path, "re");
330 if (!f)
331 return 0;
332
333 while (getline(&line, &linelen, f) != -1) {
334 ssize_t l = snprintf(cache, cache_size, "%s", line);
335 if (l < 0)
336 return log_error(0, "Failed to write cache");
337 if (l >= cache_size)
338 return log_error(0, "Write to cache was truncated");
339
340 cache += l;
341 cache_size -= l;
342 total_len += l;
343 }
344
345 d->size = total_len;
346 if (total_len > size)
347 total_len = size;
348
349 /* read from off 0 */
350 memcpy(buf, d->buf, total_len);
351
352 if (d->size > total_len)
353 d->cached = d->size - total_len;
354
355 return total_len;
356 }
357
358 int read_file_fuse_with_offset(const char *path, char *buf, size_t size,
359 off_t offset, struct file_info *d)
360 {
361 if (offset) {
362 ssize_t total_len = 0;
363 char *cache = d->buf;
364 int left;
365
366 if (offset > d->size)
367 return -EINVAL;
368
369 if (!d->cached)
370 return 0;
371
372 left = d->size - offset;
373 total_len = left > size ? size : left;
374 memcpy(buf, cache + offset, total_len);
375
376 return total_len;
377 }
378
379 return read_file_fuse(path, buf, size, d);
380 }
381
382 #define INITSCOPE "/init.scope"
383 void prune_init_slice(char *cg)
384 {
385 char *point;
386 size_t cg_len = strlen(cg), initscope_len = strlen(INITSCOPE);
387
388 if (cg_len < initscope_len)
389 return;
390
391 point = cg + cg_len - initscope_len;
392 if (strcmp(point, INITSCOPE) == 0) {
393 if (point == cg)
394 *(point + 1) = '\0';
395 else
396 *point = '\0';
397 }
398 }
399
400 int wait_for_pid(pid_t pid)
401 {
402 int status, ret;
403
404 if (pid <= 0)
405 return -1;
406
407 again:
408 ret = waitpid(pid, &status, 0);
409 if (ret == -1) {
410 if (errno == EINTR)
411 goto again;
412 return -1;
413 }
414 if (ret != pid)
415 goto again;
416 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
417 return -1;
418 return 0;
419 }
420
421 static ssize_t read_nointr(int fd, void *buf, size_t count)
422 {
423 ssize_t ret;
424 again:
425 ret = read(fd, buf, count);
426 if (ret < 0 && errno == EINTR)
427 goto again;
428
429 return ret;
430 }
431
432 static void *must_realloc(void *orig, size_t sz)
433 {
434 void *ret;
435
436 do {
437 ret = realloc(orig, sz);
438 } while (!ret);
439
440 return ret;
441 }
442
443 static char *fd_to_buf(int fd, size_t *length)
444 {
445 __do_free char *copy = NULL;
446
447 if (!length)
448 return NULL;
449
450 *length = 0;
451 for (;;) {
452 ssize_t bytes_read;
453 char buf[4096];
454 char *old = copy;
455
456 bytes_read = read_nointr(fd, buf, sizeof(buf));
457 if (bytes_read < 0)
458 return NULL;
459
460 if (!bytes_read)
461 break;
462
463 copy = must_realloc(old, (*length + bytes_read) * sizeof(*old));
464 memcpy(copy + *length, buf, bytes_read);
465 *length += bytes_read;
466 }
467
468 return move_ptr(copy);
469 }
470
471 static char *file_to_buf(const char *path, size_t *length)
472 {
473 __do_close int fd = -EBADF;
474
475 if (!length)
476 return NULL;
477
478 fd = open(path, O_RDONLY | O_CLOEXEC);
479 if (fd < 0)
480 return NULL;
481
482 return fd_to_buf(fd, length);
483 }
484
485 FILE *fopen_cached(const char *path, const char *mode, void **caller_freed_buffer)
486 {
487 __do_free char *buf = NULL;
488 size_t len = 0;
489 FILE *f;
490
491 buf = file_to_buf(path, &len);
492 if (!buf)
493 return NULL;
494
495 f = fmemopen(buf, len, mode);
496 if (!f)
497 return NULL;
498 *caller_freed_buffer = move_ptr(buf);
499 return f;
500 }
501
502 FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer)
503 {
504 __do_free char *buf = NULL;
505 size_t len = 0;
506 FILE *f;
507
508 buf = fd_to_buf(fd, &len);
509 if (!buf)
510 return NULL;
511
512 f = fmemopen(buf, len, mode);
513 if (!f)
514 return NULL;
515
516 *caller_freed_buffer = move_ptr(buf);
517 return f;
518 }
519
520 ssize_t write_nointr(int fd, const void *buf, size_t count)
521 {
522 ssize_t ret;
523
524 do {
525 ret = write(fd, buf, count);
526 } while (ret < 0 && errno == EINTR);
527
528 return ret;
529 }
530
531 int safe_uint64(const char *numstr, uint64_t *converted, int base)
532 {
533 char *err = NULL;
534 uint64_t u;
535
536 while (isspace(*numstr))
537 numstr++;
538
539 if (*numstr == '-')
540 return -EINVAL;
541
542 errno = 0;
543 u = strtoull(numstr, &err, base);
544 if (errno == ERANGE && u == UINT64_MAX)
545 return -ERANGE;
546
547 if (err == numstr || *err != '\0')
548 return -EINVAL;
549
550 *converted = u;
551 return 0;
552 }
553
554 static int char_left_gc(const char *buffer, size_t len)
555 {
556 size_t i;
557
558 for (i = 0; i < len; i++) {
559 if (buffer[i] == ' ' ||
560 buffer[i] == '\t')
561 continue;
562
563 return i;
564 }
565
566 return 0;
567 }
568
569 static int char_right_gc(const char *buffer, size_t len)
570 {
571 int i;
572
573 for (i = len - 1; i >= 0; i--) {
574 if (buffer[i] == ' ' ||
575 buffer[i] == '\t' ||
576 buffer[i] == '\n' ||
577 buffer[i] == '\0')
578 continue;
579
580 return i + 1;
581 }
582
583 return 0;
584 }
585
586 char *trim_whitespace_in_place(char *buffer)
587 {
588 buffer += char_left_gc(buffer, strlen(buffer));
589 buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
590 return buffer;
591 }