#include #include "lve_os_compat.h" #include "lve_global_params.h" static unsigned int sysctl_params[LVE_PARAM_MAX]; static int zero; static int one = 1; /* Proxy calls to be in sync with global params */ static int proxy_proc_dointvec(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { int ret; int index = ((unsigned int *)table->data) - sysctl_params; if (table->extra1 == NULL && table->extra2 == NULL) ret = proc_dointvec(table, write, buffer, lenp, ppos); else ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); if (ret != 0) goto out; if (write) ret = lve_set_param(index, sysctl_params[index]); out: return ret; } #define LVE_SYSCTL_GENERIC(name, index) \ { \ .procname = name, \ .data = &sysctl_params[index],\ .maxlen = sizeof(sysctl_params[index]),\ .mode = 0600, \ .proc_handler = proxy_proc_dointvec, \ } #define LVE_SYSCTL_BOOLEAN(name, index) \ { \ .procname = name, \ .data = &sysctl_params[index],\ .maxlen = sizeof(sysctl_params[index]),\ .mode = 0600, \ .proc_handler = proxy_proc_dointvec, \ .extra1 = &zero, \ .extra2 = &one, \ } static struct ctl_table lve_sysctl_table[] = { #if FEAT_LINK_PROT == 1 LVE_SYSCTL_BOOLEAN("protected_symlinks_create",\ LVE_SYMLINK_PROTECTION), LVE_SYSCTL_BOOLEAN("protected_hardlinks_create",\ LVE_HARDLINK_PROTECTION), LVE_SYSCTL_GENERIC("protected_symlinks_allow_gid",\ LVE_SYMLINK_PROT_ALLOW_GID), LVE_SYSCTL_GENERIC("protected_hardlinks_allow_gid",\ LVE_HARDLINK_PROT_ALLOW_GID), LVE_SYSCTL_GENERIC("enforce_symlinksifowner",\ LVE_HANDLE_SYMLINK_OWNER), LVE_SYSCTL_GENERIC("process_symlinks_by_task",\ LVE_HANDLE_SYMLINK_BY_TASK), LVE_SYSCTL_GENERIC("process_symlinks_proc",\ LVE_HANDLE_SYMLINK_PROC), LVE_SYSCTL_GENERIC("symlinkown_gid",\ LVE_SYMLINK_OWNER_GID), LVE_SYSCTL_GENERIC("global_root_enable",\ LVE_GLOBAL_NONROOT), #endif #if defined(FEAT_PROC_PROT) LVE_SYSCTL_GENERIC("proc_can_see_other_uid",\ LVE_PROC_CAN_SEE_OTHER_UID), LVE_SYSCTL_GENERIC("proc_super_gid",\ LVE_PROC_SUPER_GID), #endif {} }; static struct ctl_table_header *fs_header; static struct ctl_path fs_path[] = { { .procname = "fs", }, {}, }; #ifdef FEAT_XFS_QUOTA static struct ctl_table lve_sysctl_xfs_table[] = { LVE_SYSCTL_BOOLEAN("cap_res_quota_disable",\ LVE_XFS_QUOTA_CAP_RES_BYPASS), {} }; static struct ctl_table_header *fs_xfs_header; static struct ctl_path fs_xfs_path[] = { { .procname = "fs", }, { .procname = "xfs", }, {}, }; #endif static struct ctl_table lve_kernel_sysctl_table[] = { LVE_SYSCTL_BOOLEAN("proc_disable_net",\ LVE_PROC_DISABLE_NET), LVE_SYSCTL_BOOLEAN("memstat_nocache",\ LVE_MEMSTAT_NO_CACHE), #ifndef HAVE_USER_PTRACE_ENABLED LVE_SYSCTL_BOOLEAN("user_ptrace",\ LVE_PTRACE_ENABLED), LVE_SYSCTL_BOOLEAN("user_ptrace_self",\ LVE_PTRACE_SELF_ENABLED), #endif {} }; static struct ctl_table_header *kernel_sysctl_header; static struct ctl_path kernel_sysctl_path[] = { { .procname = "kernel", }, {}, }; static int init_from_global_params(void) { int ret = 0, index; for (index = 1; index < LVE_PARAM_MAX; index++) { uint64_t val; ret = lve_get_param(index, &val); if (ret == -ENODATA) return 0; if (ret != 0) return ret; sysctl_params[index] = (unsigned int)val; } return ret; } int __init lve_sysctl_init(void) { int ret = 0; ret = init_from_global_params(); if (ret != 0) return ret; fs_header = register_sysctl_paths(fs_path, lve_sysctl_table); if (fs_header == NULL) { pr_err("Cannot register lve_sysctl_table\n"); ret = -ENOMEM; goto out; } #ifdef FEAT_XFS_QUOTA fs_xfs_header = register_sysctl_paths(fs_xfs_path, lve_sysctl_xfs_table); if (fs_xfs_header == NULL) { pr_err("Cannot register lve_sysctl_xfs_table\n"); unregister_sysctl_table(fs_header); ret = -ENOMEM; } kernel_sysctl_header = register_sysctl_paths(kernel_sysctl_path, lve_kernel_sysctl_table); if (kernel_sysctl_header == NULL) { pr_err("Cannot register lve_kernel_sysctl_table\n"); ret = -ENOMEM; goto out; } #endif out: return ret; } void lve_sysctl_fini(void) { #ifdef FEAT_XFS_QUOTA unregister_sysctl_table(fs_xfs_header); unregister_sysctl_table(kernel_sysctl_header); #endif unregister_sysctl_table(fs_header); }