/* * Support for permanently empty directories. * Must be non-empty to avoid sharing an address with other tables.
*/ staticconststruct ctl_table sysctl_mount_point[] = {
{ }
};
/** * register_sysctl_mount_point() - registers a sysctl mount point * @path: path for the mount point * * Used to create a permanently empty directory to serve as mount point. * There are some subtle but important permission checks this allows in the * case of unprivileged mounts.
*/ struct ctl_table_header *register_sysctl_mount_point(constchar *path)
{ return register_sysctl_sz(path, sysctl_mount_point, 0);
}
EXPORT_SYMBOL(register_sysctl_mount_point);
/* Is this a permanently empty directory? */ if (sysctl_is_perm_empty_ctl_header(dir_h)) return -EROFS;
/* Am I creating a permanently empty directory? */ if (sysctl_is_perm_empty_ctl_header(header)) { if (!RB_EMPTY_ROOT(&dir->root)) return -EINVAL;
sysctl_set_perm_empty_ctl_header(dir_h);
}
staticvoid start_unregistering(struct ctl_table_header *p)
{ /* will reacquire if has to wait */
lockdep_assert_held(&sysctl_lock);
/* * if p->used is 0, nobody will ever touch that entry again; * we'll eliminate all paths to it before dropping sysctl_lock
*/ if (unlikely(p->used)) { struct completion wait;
init_completion(&wait);
p->unregistering = &wait;
spin_unlock(&sysctl_lock);
wait_for_completion(&wait);
} else { /* anything non-NULL; we'll never dereference it */
p->unregistering = ERR_PTR(-EINVAL);
spin_unlock(&sysctl_lock);
} /* * Invalidate dentries for unregistered sysctls: namespaced sysctls * can have duplicate names and contaminate dcache very badly.
*/
proc_sys_invalidate_dcache(p); /* * do not remove from the list until nobody holds it; walking the * list in do_sysctl() relies on that.
*/
spin_lock(&sysctl_lock);
erase_header(p);
}
staticstruct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
{
BUG_ON(!head);
spin_lock(&sysctl_lock); if (!use_table(head))
head = ERR_PTR(-ENOENT);
spin_unlock(&sysctl_lock); return head;
}
/* * At this point we know that the sysctl was not unregistered * and won't be until we finish.
*/
error = -EPERM; if (sysctl_perm(head, table, write ? MAY_WRITE : MAY_READ)) goto out;
/* if that can happen at all, it should be -EINVAL, not -EISDIR */
error = -EINVAL; if (!table->proc_handler) goto out;
/* don't even try if the size is too large */
error = -ENOMEM; if (count >= KMALLOC_MAX_SIZE) goto out;
kbuf = kvzalloc(count + 1, GFP_KERNEL); if (!kbuf) goto out;
if (write) {
error = -EFAULT; if (!copy_from_iter_full(kbuf, count, iter)) goto out_free_buf;
kbuf[count] = '\0';
}
staticint proc_sys_permission(struct mnt_idmap *idmap, struct inode *inode, int mask)
{ /* * sysctl entries that are not writeable, * are _NOT_ writeable, capabilities or not.
*/ struct ctl_table_header *head; conststruct ctl_table *table; int error;
/* Executable files are not allowed under /proc/sys/ */ if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) return -EACCES;
head = grab_header(inode); if (IS_ERR(head)) return PTR_ERR(head);
table = PROC_I(inode)->sysctl_entry; if (!table) /* global root - r-xr-xr-x */
error = mask & MAY_WRITE ? -EACCES : 0; else/* Use the permissions on the sysctl table entry */
error = sysctl_perm(head, table, mask & ~MAY_NOT_BLOCK);
/** * get_subdir - find or create a subdir with the specified name. * @dir: Directory to create the subdirectory in * @name: The name of the subdirectory to find or create * @namelen: The length of name * * Takes a directory with an elevated reference count so we know that * if we drop the lock the directory will not go away. Upon success * the reference is moved from @dir to the returned subdirectory. * Upon error an error code is returned and the reference on @dir is * simply dropped.
*/ staticstruct ctl_dir *get_subdir(struct ctl_dir *dir, constchar *name, int namelen)
{ struct ctl_table_set *set = dir->header.set; struct ctl_dir *subdir, *new = NULL; int err;
spin_lock(&sysctl_lock);
subdir = find_subdir(dir, name, namelen); if (!IS_ERR(subdir)) goto found; if (PTR_ERR(subdir) != -ENOENT) goto failed;
spin_unlock(&sysctl_lock); new = new_dir(set, name, namelen);
spin_lock(&sysctl_lock);
subdir = ERR_PTR(-ENOMEM); if (!new) goto failed;
/* Was the subdir added while we dropped the lock? */
subdir = find_subdir(dir, name, namelen); if (!IS_ERR(subdir)) goto found; if (PTR_ERR(subdir) != -ENOENT) goto failed;
/* Nope. Use the our freshly made directory entry. */
err = insert_header(dir, &new->header);
subdir = ERR_PTR(err); if (err) goto failed;
subdir = new;
found:
subdir->header.nreg++;
failed: if (IS_ERR(subdir)) {
pr_err("sysctl could not get directory: ");
sysctl_print_dir(dir);
pr_cont("%*.*s %ld\n", namelen, namelen, name,
PTR_ERR(subdir));
}
drop_sysctl_table(&dir->header); if (new)
drop_sysctl_table(&new->header);
spin_unlock(&sysctl_lock); return subdir;
}
if ((table->proc_handler == proc_douintvec) ||
(table->proc_handler == proc_douintvec_minmax)) { if (table->maxlen != sizeof(unsignedint))
err |= sysctl_err(path, table, "array not allowed");
}
if (table->proc_handler == proc_dou8vec_minmax) { if (table->maxlen != sizeof(u8))
err |= sysctl_err(path, table, "array not allowed");
if (table->extra1) {
extra = *(unsignedint *) table->extra1; if (extra > 255U)
err |= sysctl_err(path, table, "range value too large for proc_dou8vec_minmax");
} if (table->extra2) {
extra = *(unsignedint *) table->extra2; if (extra > 255U)
err |= sysctl_err(path, table, "range value too large for proc_dou8vec_minmax");
}
}
if (table->proc_handler == proc_dobool) { if (table->maxlen != sizeof(bool))
err |= sysctl_err(path, table, "array not allowed");
}
if (header->ctl_table_size == 0 ||
sysctl_is_perm_empty_ctl_header(header)) returntrue;
/* Are there links available for every entry in table? */
list_for_each_table_entry(entry, header) { constchar *procname = entry->procname;
link = find_entry(&tmp_head, dir, procname, strlen(procname)); if (!link) returnfalse; if (S_ISDIR(link->mode) && S_ISDIR(entry->mode)) continue; if (S_ISLNK(link->mode) && (link->data == link_root)) continue; returnfalse;
}
/* The checks passed. Increase the registration count on the links */
list_for_each_table_entry(entry, header) { constchar *procname = entry->procname;
link = find_entry(&tmp_head, dir, procname, strlen(procname));
tmp_head->nreg++;
} returntrue;
}
/* Find the directory for the ctl_table. If one is not found create it. */ staticstruct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, constchar *path)
{ constchar *name, *nextname;
for (name = path; name; name = nextname) { int namelen;
nextname = strchr(name, '/'); if (nextname) {
namelen = nextname - name;
nextname++;
} else {
namelen = strlen(name);
} if (namelen == 0) continue;
/* * namelen ensures if name is "foo/bar/yay" only foo is * registered first. We traverse as if using mkdir -p and * return a ctl_dir for the last directory entry.
*/
dir = get_subdir(dir, name, namelen); if (IS_ERR(dir)) break;
} return dir;
}
/** * __register_sysctl_table - register a leaf sysctl table * @set: Sysctl tree to register on * @path: The path to the directory the sysctl table is in. * * @table: the top-level table structure. This table should not be free'd * after registration. So it should not be used on stack. It can either * be a global or dynamically allocated by the caller and free'd later * after sysctl unregistration. * @table_size : The number of elements in table * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. * * The members of the &struct ctl_table structure are used as follows: * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not * enter a sysctl file * data - a pointer to data for use by proc_handler * maxlen - the maximum size in bytes of the data * mode - the file permissions for the /proc/sys file * type - Defines the target type (described in struct definition) * proc_handler - the text handler routine (described below) * * extra1, extra2 - extra pointers usable by the proc handler routines * XXX: we should eventually modify these to use long min / max [0] * [0] https://lkml.kernel.org/87zgpte9o4.fsf@email.froward.int.ebiederm.org * * Leaf nodes in the sysctl tree will be represented by a single file * under /proc; non-leaf nodes are not allowed. * * There must be a proc_handler routine for any terminal nodes. * Several default handlers are available to cover common cases - * * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(), * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(), * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax() * * It is the handler's job to read the input buffer from user memory * and process it. The handler should return 0 on success. * * This routine returns %NULL on a failure to register, and a pointer * to the table header on success.
*/ struct ctl_table_header *__register_sysctl_table( struct ctl_table_set *set, constchar *path, conststruct ctl_table *table, size_t table_size)
{ struct ctl_table_root *root = set->dir.header.root; struct ctl_table_header *header; struct ctl_dir *dir; struct ctl_node *node;
/** * register_sysctl_sz - register a sysctl table * @path: The path to the directory the sysctl table is in. If the path * doesn't exist we will create it for you. * @table: the table structure. The calller must ensure the life of the @table * will be kept during the lifetime use of the syctl. It must not be freed * until unregister_sysctl_table() is called with the given returned table * with this registration. If your code is non modular then you don't need * to call unregister_sysctl_table() and can instead use something like * register_sysctl_init() which does not care for the result of the syctl * registration. * @table_size: The number of elements in table. * * Register a sysctl table. @table should be a filled in ctl_table * array. A completely 0 filled entry terminates the table. * * See __register_sysctl_table for more details.
*/ struct ctl_table_header *register_sysctl_sz(constchar *path, conststruct ctl_table *table,
size_t table_size)
{ return __register_sysctl_table(&sysctl_table_root.default_set,
path, table, table_size);
}
EXPORT_SYMBOL(register_sysctl_sz);
/** * __register_sysctl_init() - register sysctl table to path * @path: path name for sysctl base. If that path doesn't exist we will create * it for you. * @table: This is the sysctl table that needs to be registered to the path. * The caller must ensure the life of the @table will be kept during the * lifetime use of the sysctl. * @table_name: The name of sysctl table, only used for log printing when * registration fails * @table_size: The number of elements in table * * The sysctl interface is used by userspace to query or modify at runtime * a predefined value set on a variable. These variables however have default * values pre-set. Code which depends on these variables will always work even * if register_sysctl() fails. If register_sysctl() fails you'd just loose the * ability to query or modify the sysctls dynamically at run time. Chances of * register_sysctl() failing on init are extremely low, and so for both reasons * this function does not return any error as it is used by initialization code. * * Context: if your base directory does not exist it will be created for you.
*/ void __init __register_sysctl_init(constchar *path, conststruct ctl_table *table, constchar *table_name, size_t table_size)
{ struct ctl_table_header *hdr = register_sysctl_sz(path, table, table_size);
if (unlikely(!hdr)) {
pr_err("failed when register_sysctl_sz %s to %s\n", table_name, path); return;
}
kmemleak_not_leak(hdr);
}
if (parent) {
put_links(header);
start_unregistering(header);
}
if (!--header->count)
kfree_rcu(header, rcu);
if (parent)
drop_sysctl_table(&parent->header);
}
/** * unregister_sysctl_table - unregister a sysctl table hierarchy * @header: the header returned from register_sysctl or __register_sysctl_table * * Unregisters the sysctl table and all children. proc entries may not * actually be removed until they are no longer used by anyone.
*/ void unregister_sysctl_table(struct ctl_table_header * header)
{
might_sleep();
/* * Historically some settings had both sysctl and a command line parameter. * With the generic sysctl. parameter support, we can handle them at a single * place and only keep the historical name for compatibility. This is not meant * to add brand new aliases. When adding existing aliases, consider whether * the possibly different moment of changing the value (e.g. from early_param * to the moment do_sysctl_args() is called) is an issue for the specific * parameter.
*/ staticconststruct sysctl_alias sysctl_aliases[] = {
{"hardlockup_all_cpu_backtrace", "kernel.hardlockup_all_cpu_backtrace" },
{"hung_task_panic", "kernel.hung_task_panic" },
{"numa_zonelist_order", "vm.numa_zonelist_order" },
{"softlockup_all_cpu_backtrace", "kernel.softlockup_all_cpu_backtrace" },
{ }
};
if (!val) return -EINVAL;
len = strlen(val); if (len == 0) return -EINVAL;
/* * To set sysctl options, we use a temporary mount of proc, look up the * respective sys/ file and write to it. To avoid mounting it when no * options were given, we mount it only when the first sysctl option is * found. Why not a persistent mount? There are problems with a * persistent mount of proc in that it forces userspace not to use any * proc mount options.
*/ if (!*proc_mnt) {
proc_fs_type = get_fs_type("proc"); if (!proc_fs_type) {
pr_err("Failed to find procfs to set sysctl from command line\n"); return 0;
}
*proc_mnt = kern_mount(proc_fs_type);
put_filesystem(proc_fs_type); if (IS_ERR(*proc_mnt)) {
pr_err("Failed to mount procfs to set sysctl from command line\n"); return 0;
}
}
path = kasprintf(GFP_KERNEL, "sys/%s", param); if (!path)
panic("%s: Failed to allocate path for %s\n", __func__, param);
strreplace(path, '.', '/');
file = file_open_root_mnt(*proc_mnt, path, O_WRONLY, 0); if (IS_ERR(file)) {
err = PTR_ERR(file); if (err == -ENOENT)
pr_err("Failed to set sysctl parameter '%s=%s': parameter not found\n",
param, val); elseif (err == -EACCES)
pr_err("Failed to set sysctl parameter '%s=%s': permission denied (read-only?)\n",
param, val); else
pr_err("Error %pe opening proc file to set sysctl parameter '%s=%s'\n",
file, param, val); goto out;
}
wret = kernel_write(file, val, len, &pos); if (wret < 0) {
err = wret; if (err == -EINVAL)
pr_err("Failed to set sysctl parameter '%s=%s': invalid value\n",
param, val); else
pr_err("Error %pe writing to proc file to set sysctl parameter '%s=%s'\n",
ERR_PTR(err), param, val);
} elseif (wret != len) {
pr_err("Wrote only %zd bytes of %d writing to proc file %s to set sysctl parameter '%s=%s\n",
wret, len, path, param, val);
}
err = filp_close(file, NULL); if (err)
pr_err("Error %pe closing proc file to set sysctl parameter '%s=%s\n",
ERR_PTR(err), param, val);
out:
kfree(path); return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.