static int run_service(struct interp *itable, struct daemon_service *service) { const char *path; int enabled = service->enabled; loginfo("Request %s for '%s'", service->name, itable[INTERP_SLOT_DIR].value); if (!enabled && !service->overridable) { logerror("'%s': service not enabled.", service->name); errno = EACCES; return -1; } if (!(path = path_ok(itable))) return -1; /* * Security on the cheap. * * We want a readable HEAD, usable "objects" directory, and * a "git-daemon-export-ok" flag that says that the other side * is ok with us doing this. * * path_ok() uses enter_repo() and does whitelist checking. * We only need to make sure the repository is exported. */ if (!export_all_trees && access("git-daemon-export-ok", F_OK)) { logerror("'%s': repository not exported.", path); errno = EACCES; return -1; } if (service->overridable) { service_looking_at = service; service_enabled = -1; git_config(git_daemon_config, NULL); if (0 <= service_enabled) enabled = service_enabled; } if (!enabled) { logerror("'%s': service not enabled for '%s'", service->name, path); errno = EACCES; return -1; } /* * We'll ignore SIGTERM from now on, we have a * good client. */ signal(SIGTERM, SIG_IGN); return service->fn(); }
asmlinkage int virt_getcwd(char *buf, unsigned long size) { int ret; char *cwd; unsigned long cwdlen; char *page; char *newcwd; unsigned long newlen; ret = (*orig_getcwd)(buf, size); if(!cwd_virtual() || ret < 0) return ret; if(!path_ok(current->fs->pwd)) return -ENOENT; page = (char *) __get_free_page(GFP_USER); if(!page) return -ENOMEM; cwd = path_pwd(page); cwdlen = PAGE_SIZE + (page - cwd) - 1; if(cwdlen >= OVERLAY_DIR_LEN && strncmp(cwd, OVERLAY_DIR, OVERLAY_DIR_LEN) == 0) { if(cwdlen == OVERLAY_DIR_LEN) { newcwd = "/"; newlen = 1; } else { newcwd = cwd + OVERLAY_DIR_LEN; newlen = cwdlen - OVERLAY_DIR_LEN; } ret = -ERANGE; if(newlen + 1 <= size) { ret = newlen + 1; if(copy_to_user(buf, newcwd, newlen + 1)) ret = -EFAULT; } } free_page((unsigned long) page); return ret; }
static char *get_abs_path(const char *filename) { char *cwd; int cwdlen, fnamelen; char *abspath, *s; char *page; if(!path_ok(current->fs->pwd)) return NULL; page = (char *) __get_free_page(GFP_USER); if(!page) return NULL; cwd = path_pwd(page); cwdlen = (unsigned int) page + PAGE_SIZE - (unsigned int) cwd - 1; if(cwd_virtual() && cwdlen > OVERLAY_DIR_LEN) { cwd += OVERLAY_DIR_LEN; cwdlen -= OVERLAY_DIR_LEN; } fnamelen = strlen(filename); abspath = kmalloc(cwdlen + 1 + fnamelen + 1, GFP_USER); if(abspath) { s = abspath; strncpy(s, cwd, cwdlen); s += cwdlen; *s++ = '/'; strncpy(s, filename, fnamelen + 1); } free_page((unsigned long) page); return abspath; }
static bool check_path(const char *path, VALUE *out, int *type) { char *p = strrchr(path, '.'); if (p != NULL) { // The given path already contains a file extension. Let's check if // it's a valid one, then try to validate the path. int t = 0; if (strcmp(p + 1, "rb") == 0) { t = TYPE_RB; } else if (rbo_enabled && strcmp(p + 1, "rbo") == 0) { t = TYPE_RBO; } else if (strcmp(p + 1, "bundle") == 0) { t = TYPE_BUNDLE; } else if (strcmp(p + 1, "so") == 0) { const char *ext = "bundle"; const long ext_len = strlen(ext); const long len = p - path; if (len + ext_len + 1 < PATH_MAX) { char buf[PATH_MAX]; strncpy(buf, path, PATH_MAX); strcpy(buf + len + 1, ext); buf[PATH_MAX - 1] = '\0'; if (path_ok(buf, out)) { *type = TYPE_BUNDLE; return true; } } } if (t != 0 && path_ok(path, out)) { *type = t; return true; } } // No valid extension, let's append the valid ones and try to validate // the path. char buf[PATH_MAX]; if (rbo_enabled) { snprintf(buf, sizeof buf, "%s.rbo", path); if (path_ok(buf, out)) { *type = TYPE_RBO; return true; } } snprintf(buf, sizeof buf, "%s.rb", path); if (path_ok(buf, out)) { *type = TYPE_RB; return true; } snprintf(buf, sizeof buf, "%s.bundle", path); if (path_ok(buf, out)) { *type = TYPE_BUNDLE; return true; } return false; }
static int run_service(char *dir, struct daemon_service *service) { const char *path; int enabled = service->enabled; loginfo("Request %s for '%s'", service->name, dir); if (!enabled && !service->overridable) { logerror("'%s': service not enabled.", service->name); errno = EACCES; return daemon_error(dir, "service not enabled"); } if (!(path = path_ok(dir))) return daemon_error(dir, "no such repository"); /* * Security on the cheap. * * We want a readable HEAD, usable "objects" directory, and * a "git-daemon-export-ok" flag that says that the other side * is ok with us doing this. * * path_ok() uses enter_repo() and does whitelist checking. * We only need to make sure the repository is exported. */ if (!export_all_trees && access("git-daemon-export-ok", F_OK)) { logerror("'%s': repository not exported.", path); errno = EACCES; return daemon_error(dir, "repository not exported"); } if (service->overridable) { service_looking_at = service; service_enabled = -1; git_config(git_daemon_config, NULL); if (0 <= service_enabled) enabled = service_enabled; } if (!enabled) { logerror("'%s': service not enabled for '%s'", service->name, path); errno = EACCES; return daemon_error(dir, "service not enabled"); } /* * Optionally, a hook can choose to deny access to the * repository depending on the phase of the moon. */ if (access_hook && run_access_hook(service, dir, path)) return -1; /* * We'll ignore SIGTERM from now on, we have a * good client. */ signal(SIGTERM, SIG_IGN); return service->fn(); }
static void cache_cleaner_thread(void *none) { /* Find where it all happens */ char covers_path[PATH_MAX]; if (make_cache_root_path(covers_path, PATH_MAX-10)) { return; } strcat(covers_path, "covers"); const size_t covers_path_length = strlen(covers_path); deadbeef->mutex_lock(thread_mutex); while (!terminate) { time_t oldest_mtime = time(NULL); /* Loop through the artist directories */ DIR *covers_dir = opendir(covers_path); struct dirent *covers_subdir; while (!terminate && covers_dir && (covers_subdir = readdir(covers_dir))) { const int32_t cache_secs = cache_expiry_seconds; deadbeef->mutex_unlock(thread_mutex); if (cache_secs > 0 && path_ok(covers_path_length, covers_subdir->d_name)) { trace("Analyse %s for expired files\n", covers_subdir->d_name); const time_t cache_expiry = time(NULL) - cache_secs; /* Loop through the image files in this artist directory */ char subdir_path[PATH_MAX]; sprintf(subdir_path, "%s/%s", covers_path, covers_subdir->d_name); const size_t subdir_path_length = strlen(subdir_path); DIR *subdir = opendir(subdir_path); struct dirent *entry; while (subdir && (entry = readdir(subdir))) { if (path_ok(subdir_path_length, entry->d_name)) { char entry_path[PATH_MAX]; sprintf(entry_path, "%s/%s", subdir_path, entry->d_name); /* Test against the cache expiry time (cache invalidation resets are not handled here) */ struct stat stat_buf; if (!stat(entry_path, &stat_buf)) { if (stat_buf.st_mtime <= cache_expiry) { trace("%s expired from cache\n", entry_path); remove_cache_item(entry_path, subdir_path, covers_subdir->d_name, entry->d_name); } else if (stat_buf.st_mtime < oldest_mtime) { oldest_mtime = stat_buf.st_mtime; } } } } if (subdir) { closedir (subdir); } } usleep(100000); deadbeef->mutex_lock(thread_mutex); } if (covers_dir) { closedir (covers_dir); covers_dir = NULL; } /* Sleep until just after the oldest file expires */ if (cache_expiry_seconds > 0 && !terminate) { struct timespec wake_time = { .tv_sec = time(NULL) + max(60, oldest_mtime - time(NULL) + cache_expiry_seconds), .tv_nsec = 999999 }; trace("Cache cleaner sleeping for %d seconds\n", max(60, oldest_mtime - time(NULL) + cache_expiry_seconds)); pthread_cond_timedwait((pthread_cond_t *)thread_cond, (pthread_mutex_t *)thread_mutex, &wake_time); } /* Just go back to sleep if cache expiry is disabled */ while (cache_expiry_seconds <= 0 && !terminate) { trace("Cache cleaner sleeping forever\n"); pthread_cond_wait((pthread_cond_t *)thread_cond, (pthread_mutex_t *)thread_mutex); } } deadbeef->mutex_unlock(thread_mutex); } void cache_configchanged(void) { const int32_t new_cache_expiry_seconds = deadbeef->conf_get_int("artwork.cache.period", 48) * 60 * 60; if (new_cache_expiry_seconds != cache_expiry_seconds) { deadbeef->mutex_lock(thread_mutex); cache_expiry_seconds = new_cache_expiry_seconds; deadbeef->cond_signal(thread_cond); deadbeef->mutex_unlock(thread_mutex); } } void stop_cache_cleaner(void) { if (tid) { deadbeef->mutex_lock(thread_mutex); terminate = 1; deadbeef->cond_signal(thread_cond); deadbeef->mutex_unlock(thread_mutex); deadbeef->thread_join(tid); tid = 0; trace("Cache cleaner thread stopped\n"); } if (thread_mutex) { deadbeef->mutex_free(thread_mutex); thread_mutex = 0; } if (thread_cond) { deadbeef->cond_free(thread_cond); thread_cond = 0; } if (files_mutex) { deadbeef->mutex_free(files_mutex); files_mutex = 0; } } int start_cache_cleaner(void) { terminate = 0; cache_expiry_seconds = deadbeef->conf_get_int("artwork.cache.period", 48) * 60 * 60; files_mutex = deadbeef->mutex_create_nonrecursive(); thread_mutex = deadbeef->mutex_create_nonrecursive(); thread_cond = deadbeef->cond_create(); if (files_mutex && thread_mutex && thread_cond) { tid = deadbeef->thread_start_low_priority(cache_cleaner_thread, NULL); trace("Cache cleaner thread started\n"); } if (!tid) { stop_cache_cleaner(); return -1; } return 0; }
static char *resolv_virt(const char *pathname, int must_exist, int flags) { struct nameidata root; struct nameidata nd; struct dentry *origroot; struct vfsmount *origrootmnt; char *newpathname = NULL; char *page = NULL; char *path = NULL; int pathlen = 0; int error; int newflags; lock_kernel(); DEB((KERN_INFO "resolve_virt pathname: '%s'\n", pathname ? pathname : "(null)")); error = a_path_walk(OVERLAY_DIR, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &root); if(error) goto out; origroot = current->fs->root; origrootmnt = current->fs->rootmnt; current->fs->root = root.dentry; current->fs->rootmnt = root.mnt; newflags = flags; if(must_exist) newflags |= LOOKUP_POSITIVE; error = a_path_walk(pathname, newflags, &nd); if(!error) { if(path_ok(nd.dentry)) { page = (char *) __get_free_page(GFP_USER); if(page) { path = d_path(nd.dentry, nd.mnt, page, PAGE_SIZE); DEB((KERN_INFO "resolve_virt path = '%s'\n", path)); pathlen = (unsigned int) page + PAGE_SIZE - (unsigned int) path; } } a_path_release(&nd); } current->fs->root = origroot; current->fs->rootmnt = origrootmnt; a_path_release(&root); if(path) { int isvirtual; error = a_path_walk(path, flags, &nd); if(!error) { if(nd.dentry->d_inode) isvirtual = 0; else if(must_exist) isvirtual = 1; else if(strchr(path, AVFS_MAGIC_CHAR)) isvirtual = 1; else isvirtual = 0; a_path_release(&nd); } else { isvirtual = 1; } if(!isvirtual) { newpathname = kmalloc(pathlen + 1, GFP_USER); if(newpathname) strncpy(newpathname, path, pathlen); } else { newpathname = kmalloc(OVERLAY_DIR_LEN + pathlen + 1, GFP_USER); if(newpathname) { strcpy(newpathname, OVERLAY_DIR); strncat(newpathname, path, pathlen); } } } if(page) free_page((unsigned long) page); DEB((KERN_INFO "resolve_virt newpathname: '%s'\n", newpathname ? newpathname : "(null)")); out: unlock_kernel(); return newpathname; }
static char *resolv_virt(const char *pathname, int must_exist, int flags) { struct dentry *root, *origroot; struct dentry *dentry; char *newpathname = NULL; char *page = NULL; char *path = NULL; int pathlen = 0; lock_kernel(); DEB((KERN_INFO "resolve_virt pathname: '%s'\n", pathname ? pathname : "(null)")); root = lookup_dentry(OVERLAY_DIR, NULL, 1); if(IS_ERR(root)) goto out; if(!root->d_inode) { dput(root); goto out; } origroot = current->fs->root; current->fs->root = root; dentry = lookup_dentry(pathname, NULL, flags); if(!IS_ERR(dentry)) { if((!must_exist || dentry->d_inode) && path_ok(dentry)) { page = (char *) __get_free_page(GFP_USER); if(page) { path = d_path(dentry, page, PAGE_SIZE); DEB((KERN_INFO "resolve_virt path = '%s'\n", path)); pathlen = (unsigned int) page + PAGE_SIZE - (unsigned int) path; } } dput(dentry); } current->fs->root = origroot; dput(root); if(path) { int isvirtual; dentry = lookup_dentry(path, NULL, flags); if(!IS_ERR(dentry)) { if(dentry->d_inode) isvirtual = 0; else if(must_exist) isvirtual = 1; else if(strchr(path, AVFS_MAGIC_CHAR)) isvirtual = 1; else isvirtual = 0; dput(dentry); } else { isvirtual = 1; } if(!isvirtual) { newpathname = kmalloc(pathlen + 1, GFP_USER); if(newpathname) strncpy(newpathname, path, pathlen); } else { newpathname = kmalloc(OVERLAY_DIR_LEN + pathlen + 1, GFP_USER); if(newpathname) { strcpy(newpathname, OVERLAY_DIR); strncat(newpathname, path, pathlen); } } } if(page) free_page((unsigned long) page); DEB((KERN_INFO "resolve_virt newpathname: '%s'\n", newpathname ? newpathname : "(null)")); out: unlock_kernel(); return newpathname; }