END_TEST START_TEST(test_filename_is_valid) { filename_t *file = NULL; ck_assert_msg(0 == filename_is_valid(file), "A NULL file is never valid."); file = (filename_t *)malloc(sizeof(filename_t)); file->name = NULL; ck_assert_msg(0 == filename_is_valid(file), "A file with a NULL name is" " never valid"); free(file); file = NULL; // +2 for the `\0` character. char buf[PATH_MAX + 2]; memset(buf, 'a', sizeof(buf)); buf[PATH_MAX + 1] = '\0'; // +1 because indexes start at 0. file = filename_ptr_create(&buf[0]); ck_assert_msg(0 == filename_is_valid(file), "A file over PATH_MAX is never" " valid."); filename_ptr_free(&file); file = filename_ptr_create("fr/og"); ck_assert_str_eq("fr/og", file->name); ck_assert_msg(0 == filename_is_valid(file), "A filename with a / is never" " valid."); filename_ptr_free(&file); file = filename_ptr_create("frog"); ck_assert_str_eq("frog", file->name); ck_assert_int_eq(1, filename_is_valid(file)); filename_ptr_free(&file); }
int drop_in_file(const char *dir, const char *unit, unsigned level, const char *name, char **_p, char **_q) { char prefix[DECIMAL_STR_MAX(unsigned)]; _cleanup_free_ char *b = NULL; char *p, *q; assert(unit); assert(name); assert(_p); assert(_q); sprintf(prefix, "%u", level); b = xescape(name, "/."); if (!b) return -ENOMEM; if (!filename_is_valid(b)) return -EINVAL; p = strjoin(dir, "/", unit, ".d"); if (!p) return -ENOMEM; q = strjoin(p, "/", prefix, "-", b, ".conf"); if (!q) { free(p); return -ENOMEM; } *_p = p; *_q = q; return 0; }
static int file_of_seat(const char *seat, char **_p) { char *p; int r; assert(_p); if (seat) { if (!filename_is_valid(seat)) return -EINVAL; p = strappend("/run/systemd/seats/", seat); } else { _cleanup_free_ char *buf = NULL; r = sd_session_get_seat(NULL, &buf); if (r < 0) return r; p = strappend("/run/systemd/seats/", buf); } if (!p) return -ENOMEM; *_p = TAKE_PTR(p); return 0; }
bool locale_is_valid(const char *name) { if (isempty(name)) return false; if (strlen(name) >= 128) return false; if (!utf8_is_valid(name)) return false; if (!filename_is_valid(name)) return false; if (!string_is_safe(name)) return false; return true; }
static int extract_prefix(const char *path, char **ret) { _cleanup_free_ char *name = NULL; const char *bn, *underscore; size_t m; bn = basename(path); underscore = strchr(bn, '_'); if (underscore) m = underscore - bn; else { const char *e; e = endswith(bn, ".raw"); if (!e) e = strchr(bn, 0); m = e - bn; } name = strndup(bn, m); if (!name) return -ENOMEM; /* A slightly reduced version of what's permitted in unit names. With ':' and '\' are removed, as well as '_' * which we use as delimiter for the second part of the image string, which we ignore for now. */ if (!in_charset(name, DIGITS LETTERS "-.")) return -EINVAL; if (!filename_is_valid(name)) return -EINVAL; *ret = TAKE_PTR(name); return 0; }
static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) { int interactive; const char *name; int r; assert(c); assert(m); r = sd_bus_message_read(m, "sb", &name, &interactive); if (r < 0) return r; if (isempty(name)) name = NULL; if (streq_ptr(name, c->data[prop])) return sd_bus_reply_method_return(m, NULL); /* Since the pretty hostname should always be changed at the * same time as the static one, use the same policy action for * both... */ r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info", NULL, interactive, UID_INVALID, &c->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ if (isempty(name)) { c->data[prop] = mfree(c->data[prop]); } else { char *h; /* The icon name might ultimately be used as file * name, so better be safe than sorry */ if (prop == PROP_ICON_NAME && !filename_is_valid(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name); if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name); if (prop == PROP_CHASSIS && !valid_chassis(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name); if (prop == PROP_DEPLOYMENT && !valid_deployment(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name); if (prop == PROP_LOCATION && string_has_cc(name, NULL)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name); h = strdup(name); if (!h) return -ENOMEM; free(c->data[prop]); c->data[prop] = h; } r = context_write_data_machine_info(c); if (r < 0) { log_error_errno(r, "Failed to write machine info: %m"); return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r)); } log_info("Changed %s to '%s'", prop == PROP_PRETTY_HOSTNAME ? "pretty host name" : prop == PROP_DEPLOYMENT ? "deployment" : prop == PROP_LOCATION ? "location" : prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop])); (void) sd_bus_emit_properties_changed( sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" : prop == PROP_DEPLOYMENT ? "Deployment" : prop == PROP_LOCATION ? "Location" : prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL); return sd_bus_reply_method_return(m, NULL); }
void server_process_native_file( Server *s, int fd, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) { struct stat st; bool sealed; int r; /* Data is in the passed fd, since it didn't fit in a * datagram. */ assert(s); assert(fd >= 0); /* If it's a memfd, check if it is sealed. If so, we can just * use map it and use it, and do not need to copy the data * out. */ sealed = memfd_get_sealed(fd) > 0; if (!sealed && (!ucred || ucred->uid != 0)) { _cleanup_free_ char *sl = NULL, *k = NULL; const char *e; /* If this is not a sealed memfd, and the peer is unknown or * unprivileged, then verify the path. */ if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) { log_oom(); return; } r = readlink_malloc(sl, &k); if (r < 0) { log_error_errno(r, "readlink(%s) failed: %m", sl); return; } e = path_startswith(k, "/dev/shm/"); if (!e) e = path_startswith(k, "/tmp/"); if (!e) e = path_startswith(k, "/var/tmp/"); if (!e) { log_error("Received file outside of allowed directories. Refusing."); return; } if (!filename_is_valid(e)) { log_error("Received file in subdirectory of allowed directories. Refusing."); return; } } if (fstat(fd, &st) < 0) { log_error_errno(errno, "Failed to stat passed file, ignoring: %m"); return; } if (!S_ISREG(st.st_mode)) { log_error("File passed is not regular. Ignoring."); return; } if (st.st_size <= 0) return; if (st.st_size > ENTRY_SIZE_MAX) { log_error("File passed too large. Ignoring."); return; } if (sealed) { void *p; size_t ps; /* The file is sealed, we can just map it and use it. */ ps = PAGE_ALIGN(st.st_size); p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) { log_error_errno(errno, "Failed to map memfd, ignoring: %m"); return; } server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len); assert_se(munmap(p, ps) >= 0); } else { _cleanup_free_ void *p = NULL; struct statvfs vfs; ssize_t n; if (fstatvfs(fd, &vfs) < 0) { log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); return; } /* Refuse operating on file systems that have * mandatory locking enabled, see: * * https://github.com/systemd/systemd/issues/1822 */ if (vfs.f_flag & ST_MANDLOCK) { log_error("Received file descriptor from file system with mandatory locking enable, refusing."); return; } /* Make the fd non-blocking. On regular files this has * the effect of bypassing mandatory locking. Of * course, this should normally not be necessary given * the check above, but let's better be safe than * sorry, after all NFS is pretty confusing regarding * file system flags, and we better don't trust it, * and so is SMB. */ r = fd_nonblock(fd, true); if (r < 0) { log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); return; } /* The file is not sealed, we can't map the file here, since * clients might then truncate it and trigger a SIGBUS for * us. So let's stupidly read it */ p = malloc(st.st_size); if (!p) { log_oom(); return; } n = pread(fd, p, st.st_size, 0); if (n < 0) log_error_errno(errno, "Failed to read file, ignoring: %m"); else if (n > 0) server_process_native_message(s, p, n, ucred, tv, label, label_len); } }
/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */ static int mount_legacy_cgns_unsupported( const char *dest, CGroupUnified unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context) { _cleanup_set_free_free_ Set *controllers = NULL; const char *cgroup_root; int r; cgroup_root = prefix_roota(dest, "/sys/fs/cgroup"); (void) mkdir_p(cgroup_root, 0755); /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */ r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW); if (r < 0) return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m"); if (r == 0) { _cleanup_free_ char *options = NULL; r = tmpfs_patch_options("mode=755", uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options); if (r < 0) return log_oom(); r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options); if (r < 0) return r; } r = cg_all_unified(); if (r < 0) return r; if (r > 0) goto skip_controllers; r = cg_kernel_controllers(&controllers); if (r < 0) return log_error_errno(r, "Failed to determine cgroup controllers: %m"); for (;;) { _cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL; controller = set_steal_first(controllers); if (!controller) break; origin = prefix_root("/sys/fs/cgroup/", controller); if (!origin) return log_oom(); r = readlink_malloc(origin, &combined); if (r == -EINVAL) { /* Not a symbolic link, but directly a single cgroup hierarchy */ r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true); if (r < 0) return r; } else if (r < 0) return log_error_errno(r, "Failed to read link %s: %m", origin); else { _cleanup_free_ char *target = NULL; target = prefix_root(dest, origin); if (!target) return log_oom(); /* A symbolic link, a combination of controllers in one hierarchy */ if (!filename_is_valid(combined)) { log_warning("Ignoring invalid combined hierarchy %s.", combined); continue; } r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true); if (r < 0) return r; r = symlink_idempotent(combined, target, false); if (r == -EINVAL) return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m"); if (r < 0) return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m"); } } skip_controllers: if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) { r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false); if (r < 0) return r; } r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false); if (r < 0) return r; return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL, MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755"); }
/* ================= r_texture_load ================= */ erbool r_texture_load (const char *name, int type, image_t *out_image, r_texture_t **tex) { int gltex, nlen, w, h, texw, texh; char tmp[MISC_MAX_FILENAME], *namecopy; image_t image; r_texture_t *t, clone; if (NULL == name || type < 0 || type >= STSIZE(types) || NULL == tex) { sys_printf("bad args (name=%p, type=%i, tex=%p)\n", name, type, tex); return false; } *tex = NULL; if (!filename_is_valid(name)) return false; /* check if it was loaded earlier */ clone.name = name; t = sglib_r_texture_t_find_member(textures, &clone); if (NULL != t) { t->ref++; *tex = t; return true; } snprintf(tmp, sizeof(tmp), "tex/%s", name); if (!image_load(tmp, &image)) goto error; w = image.width; h = image.height; if (NULL != out_image) { memcpy(out_image, &image, sizeof(image)); out_image->data = mem_alloc(r_mempool, w * h << 2); memcpy(out_image->data, image.data, w * h << 2); } if (!gl_texture_create(&image, types[type], &gltex, &texw, &texh)) { sys_printf("failed to create gl texture \"%s\" (%ix%i)\n", name, w, h); goto error; } mem_free(image.data); nlen = strlen(name) + 1; if (NULL == (t = mem_alloc(r_mempool, sizeof(r_texture_t) + nlen))) { gl_texture_delete(gltex); goto error; } namecopy = (char *)t + sizeof(r_texture_t); strlcpy(namecopy, name, nlen); t->name = namecopy; t->type = type; t->gltex = gltex; t->ref = 1; t->w = w; t->h = h; t->texw = (float)w / (float)texw; t->texh = (float)h / (float)texh; *tex = t; sglib_r_texture_t_add(&textures, t); return true; error: if (NULL != image.data) mem_free(image.data); return false; }