/* SPDX-License-Identifier: LGPL-2.1+ */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#ifndef FUSE_USE_VERSION
-#define FUSE_USE_VERSION 26
-#endif
-
-#define _FILE_OFFSET_BITS 64
+#include "config.h"
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <fuse.h>
#include <inttypes.h>
#include <sched.h>
#include <stdarg.h>
-#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
+#include "utils.h"
+
#include "bindings.h"
-#include "config.h"
#include "macro.h"
#include "memory_utils.h"
-#include "utils.h"
-/*
- * append the given formatted string to *src.
- * src: a pointer to a char* in which to append the formatted string.
- * sz: the number of characters printed so far, minus trailing \0.
- * asz: the allocated size so far
- * format: string format. See printf for details.
- * ...: varargs. See printf for details.
- */
/*
* append the given formatted string to *src.
* src: a pointer to a char* in which to append the formatted string.
*/
static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns)
{
- __do_close_prot_errno int ns_fd1 = -1, ns_fd2 = -1;
+ __do_close int ns_fd1 = -1, ns_fd2 = -1;
int ret = -1;
struct stat ns_st1, ns_st2;
bool is_shared_pidns(pid_t pid)
{
+ __do_close int fd = -EBADF;
+
if (pid != 1)
return false;
- if (in_same_namespace(pid, getpid(), "pid") == -EINVAL)
+ fd = in_same_namespace(pid, getpid(), "pid");
+ if (fd == EINVAL)
return true;
return false;
bool wait_for_sock(int sock, int timeout)
{
- __do_close_prot_errno int epfd = -EBADF;
+ __do_close int epfd = -EBADF;
struct epoll_event ev;
int ret, now, starttime, deltatime;
epfd = epoll_create(1);
if (epfd < 0)
- return log_error(false, "%s\n", "Failed to create epoll socket: %m");
+ return log_error(false, "%m - Failed to create epoll socket");
ev.events = POLLIN_SET;
ev.data.fd = sock;
bool recv_creds(int sock, struct ucred *cred, char *v)
{
- struct msghdr msg = { 0 };
+ struct msghdr msg = {};
struct iovec iov;
struct cmsghdr *cmsg;
- char cmsgbuf[CMSG_SPACE(sizeof(*cred))];
- char buf[1];
- int ret;
+ ssize_t ret;
+ char cmsgbuf[CMSG_SPACE(sizeof(*cred))] = {};
+ char buf = '1';
int optval = 1;
- *v = '1';
-
- cred->pid = -1;
- cred->uid = -1;
- cred->gid = -1;
-
- if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1)
- return log_error(false, "Failed to set passcred: %s\n", strerror(errno));
-
- buf[0] = '1';
- if (write(sock, buf, 1) != 1)
- return log_error(false, "Failed to start write on scm fd: %s\n", strerror(errno));
-
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
- iov.iov_base = buf;
+ iov.iov_base = &buf;
iov.iov_len = sizeof(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
+ *v = buf;
+
+ ret = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval));
+ if (ret < 0)
+ return log_error(false, "Failed to set passcred: %s\n", strerror(errno));
+
+ ret = write_nointr(sock, &buf, sizeof(buf));
+ if (ret != sizeof(buf))
+ return log_error(false, "Failed to start write on scm fd: %s\n", strerror(errno));
+
if (!wait_for_sock(sock, 2))
return log_error(false, "Timed out waiting for scm_cred: %s\n", strerror(errno));
cmsg = CMSG_FIRSTHDR(&msg);
- if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
- cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS) {
+ if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(*cred)) &&
+ cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS) {
memcpy(cred, CMSG_DATA(cmsg), sizeof(*cred));
}
- *v = buf[0];
+ *v = buf;
return true;
}
return 0;
while (getline(&line, &linelen, f) != -1) {
- ssize_t l = snprintf(cache, cache_size, "%s", line);
+ ssize_t l;
+
+ l = snprintf(cache, cache_size, "%s", line);
if (l < 0)
return log_error(0, "Failed to write cache");
- if (l >= cache_size)
+ if ((size_t)l >= cache_size)
return log_error(0, "Write to cache was truncated");
cache += l;
/* read from off 0 */
memcpy(buf, d->buf, total_len);
- if (d->size > total_len)
+ if (d->size > (int)total_len)
d->cached = d->size - total_len;
+
return total_len;
}
+int read_file_fuse_with_offset(const char *path, char *buf, size_t size,
+ off_t offset, struct file_info *d)
+{
+ if (offset) {
+ ssize_t total_len = 0;
+ char *cache = d->buf;
+ size_t left;
+
+ if (offset > d->size)
+ return -EINVAL;
+
+ if (!d->cached)
+ return 0;
+
+ left = d->size - offset;
+ total_len = left > size ? size : left;
+ memcpy(buf, cache + offset, total_len);
+
+ return total_len;
+ }
+
+ return read_file_fuse(path, buf, size, d);
+}
+
#define INITSCOPE "/init.scope"
void prune_init_slice(char *cg)
{
static char *file_to_buf(const char *path, size_t *length)
{
- __do_close_prot_errno int fd = -EBADF;
+ __do_close int fd = -EBADF;
if (!length)
return NULL;
*caller_freed_buffer = move_ptr(buf);
return f;
}
+
+ssize_t write_nointr(int fd, const void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = write(fd, buf, count);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+int safe_uint64(const char *numstr, uint64_t *converted, int base)
+{
+ char *err = NULL;
+ uint64_t u;
+
+ while (isspace(*numstr))
+ numstr++;
+
+ if (*numstr == '-')
+ return -EINVAL;
+
+ errno = 0;
+ u = strtoull(numstr, &err, base);
+ if (errno == ERANGE && u == UINT64_MAX)
+ return -ERANGE;
+
+ if (err == numstr || *err != '\0')
+ return -EINVAL;
+
+ *converted = u;
+ return 0;
+}
+
+int safe_uint32(const char *numstr, uint32_t *converted, int base)
+{
+ char *err = NULL;
+ unsigned long uli;
+
+ while (isspace(*numstr))
+ numstr++;
+
+ if (*numstr == '-')
+ return -EINVAL;
+
+ errno = 0;
+ uli = strtoul(numstr, &err, base);
+ if (errno == ERANGE && uli == UINT32_MAX)
+ return -ERANGE;
+
+ if (err == numstr || *err != '\0')
+ return -EINVAL;
+
+ *converted = (uint32_t)uli;
+ return 0;
+}
+
+static int char_left_gc(const char *buffer, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (buffer[i] == ' ' ||
+ buffer[i] == '\t')
+ continue;
+
+ return i;
+ }
+
+ return 0;
+}
+
+static int char_right_gc(const char *buffer, size_t len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--) {
+ if (buffer[i] == ' ' ||
+ buffer[i] == '\t' ||
+ buffer[i] == '\n' ||
+ buffer[i] == '\0')
+ continue;
+
+ return i + 1;
+ }
+
+ return 0;
+}
+
+char *trim_whitespace_in_place(char *buffer)
+{
+ buffer += char_left_gc(buffer, strlen(buffer));
+ buffer[char_right_gc(buffer, strlen(buffer))] = '\0';
+ return buffer;
+}
+
+#define BATCH_SIZE 50
+static int batch_realloc(char **mem, size_t oldlen, size_t newlen)
+{
+ int newbatches = (newlen / BATCH_SIZE) + 1;
+ int oldbatches = (oldlen / BATCH_SIZE) + 1;
+
+ if (!*mem || newbatches > oldbatches) {
+ char *tmp;
+
+ tmp = realloc(*mem, newbatches * BATCH_SIZE);
+ if (!tmp)
+ return -ENOMEM;
+ *mem = tmp;
+ }
+
+ return 0;
+}
+
+static int append_line(char **dest, size_t oldlen, char *new, size_t newlen)
+{
+ int ret;
+ size_t full = oldlen + newlen;
+
+ ret = batch_realloc(dest, oldlen, full + 1);
+ if (ret)
+ return ret;
+
+ memcpy(*dest + oldlen, new, newlen + 1);
+ return 0;
+}
+
+/* Slurp in a whole file */
+char *read_file_at(int dfd, const char *fnam, unsigned int o_flags)
+{
+ __do_close int fd = -EBADF;
+ __do_free char *buf = NULL, *line = NULL;
+ __do_fclose FILE *f = NULL;
+ size_t len = 0, fulllen = 0;
+ int linelen;
+
+ fd = openat(dfd, fnam, o_flags, 0);
+ if (fd < 0)
+ return NULL;
+
+ f = fdopen(fd, "re");
+ if (!f)
+ return NULL;
+ /* Transfer ownership to fdopen(). */
+ move_fd(fd);
+
+ while ((linelen = getline(&line, &len, f)) != -1) {
+ if (append_line(&buf, fulllen, line, linelen))
+ return NULL;
+ fulllen += linelen;
+ }
+
+ return move_ptr(buf);
+}
+
+DIR *opendir_flags(const char *path, int flags)
+{
+ __do_close int dfd = -EBADF;
+ DIR *dirp;
+
+ dfd = open(path, O_DIRECTORY | flags);
+ if (dfd < 0)
+ return NULL;
+
+ dirp = fdopendir(dfd);
+ if (dirp)
+ move_fd(dfd); /* Transfer ownership to fdopendir(). */
+
+ return dirp;
+}
+
+int get_task_personality(pid_t pid, __u32 *personality)
+{
+ __do_close int fd = -EBADF;
+ int ret = -1;
+ char path[STRLITERALLEN("/proc//personality") + INTTYPE_TO_STRLEN(pid_t) + 1];
+ /* seq_printf(m, "%08x\n", task->personality); */
+ char buf[8 + 1];
+
+ ret = strnprintf(path, sizeof(path), "/proc/%d/personality", pid);
+ if (ret < 0)
+ return -1;
+
+ fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ return -1;
+
+ ret = read_nointr(fd, buf, sizeof(buf) - 1);
+ if (ret >= 0) {
+ buf[ret] = '\0';
+ if (safe_uint32(buf, personality, 16) < 0)
+ return log_error(-1, "Failed to convert personality %s", buf);
+ }
+
+ return ret;
+}