.maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, },#endif#ifdef CONFIG_MMU { .ctl_name = FS_LEASE_TIME, .procname = "lease-break-time", .data = &lease_break_time, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = FS_AIO_NR, .procname = "aio-nr", .data = &aio_nr, .maxlen = sizeof(aio_nr), .mode = 0444, .proc_handler = &proc_doulongvec_minmax, }, { .ctl_name = FS_AIO_MAX_NR, .procname = "aio-max-nr", .data = &aio_max_nr, .maxlen = sizeof(aio_max_nr), .mode = 0644, .proc_handler = &proc_doulongvec_minmax, },#ifdef CONFIG_INOTIFY_USER { .ctl_name = FS_INOTIFY, .procname = "inotify", .mode = 0555, .child = inotify_table, },#endif #endif { .ctl_name = KERN_SETUID_DUMPABLE, .procname = "suid_dumpable", .data = &suid_dumpable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = 0 }}; static ctl_table debug_table[] = { { .ctl_name = 0 }}; static ctl_table dev_table[] = { { .ctl_name = 0 }}; extern void init_irq_proc (void); static DEFINE_SPINLOCK(sysctl_lock); /* called under sysctl_lock */static int use_table(struct ctl_table_header *p){ if (unlikely(p->unregistering)) return 0; p->used++; return 1;} /* called under sysctl_lock */static void unuse_table(struct ctl_table_header *p){ if (!--p->used) if (unlikely(p->unregistering)) complete(p->unregistering);} /* called under sysctl_lock, will reacquire if has to wait */static void start_unregistering(struct ctl_table_header *p){ /* * 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); spin_lock(&sysctl_lock); } /* * do not remove from the list until nobody holds it; walking the * list in do_sysctl() relies on that. */ list_del_init(&p->ctl_entry);} void __init sysctl_init(void){#ifdef CONFIG_PROC_FS register_proc_table(root_table, proc_sys_root, &root_table_header); init_irq_proc();#endif} int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen){ struct list_head *tmp; int error = -ENOTDIR; if (nlen <= 0 || nlen >= CTL_MAXNAME) return -ENOTDIR; if (oldval) { int old_len; if (!oldlenp || get_user(old_len, oldlenp)) return -EFAULT; } spin_lock(&sysctl_lock); tmp = &root_table_header.ctl_entry; do { struct ctl_table_header *head = list_entry(tmp, struct ctl_table_header, ctl_entry); void *context = NULL; if (!use_table(head)) continue; spin_unlock(&sysctl_lock); error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->ctl_table, &context); kfree(context); spin_lock(&sysctl_lock); unuse_table(head); if (error != -ENOTDIR) break; } while ((tmp = tmp->next) != &root_table_header.ctl_entry); spin_unlock(&sysctl_lock); return error;} asmlinkage long sys_sysctl(struct __sysctl_args __user *args){ struct __sysctl_args tmp; int error; if (copy_from_user(&tmp, args, sizeof(tmp))) return -EFAULT; lock_kernel(); error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, tmp.newval, tmp.newlen); unlock_kernel(); return error;} /* * ctl_perm does NOT grant the superuser all rights automatically, because * some sysctl variables are readonly even to root. */ static int test_perm(int mode, int op){ if (!current->euid) mode >>= 6; else if (in_egroup_p(0)) mode >>= 3; if ((mode & op & 0007) == op) return 0; return -EACCES;} static inline int ctl_perm(ctl_table *table, int op){ int error; error = security_sysctl(table, op); if (error) return error; return test_perm(table->mode, op);} static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, ctl_table *table, void **context){ int n;repeat: if (!nlen) return -ENOTDIR; if (get_user(n, name)) return -EFAULT; for ( ; table->ctl_name; table++) { if (n == table->ctl_name || table->ctl_name == CTL_ANY) { int error; if (table->child) { if (ctl_perm(table, 001)) return -EPERM; if (table->strategy) { error = table->strategy( table, name, nlen, oldval, oldlenp, newval, newlen, context); if (error) return error; } name++; nlen--; table = table->child; goto repeat; } error = do_sysctl_strategy(table, name, nlen, oldval, oldlenp, newval, newlen, context); return error; } } return -ENOTDIR;} /* Perform the actual read/write of a sysctl table entry. */int do_sysctl_strategy (ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context){ int op = 0, rc; size_t len; if (oldval) op |= 004; if (newval) op |= 002; if (ctl_perm(table, op)) return -EPERM; if (table->strategy) { rc = table->strategy(table, name, nlen, oldval, oldlenp, newval, newlen, context); if (rc < 0) return rc; if (rc > 0) return 0; } /* If there is no strategy routine, or if the strategy returns * zero, proceed with automatic r/w */ if (table->data && table->maxlen) { if (oldval && oldlenp) { if (get_user(len, oldlenp)) return -EFAULT; if (len) { if (len > table->maxlen) len = table->maxlen; if(copy_to_user(oldval, table->data, len)) return -EFAULT; if(put_user(len, oldlenp)) return -EFAULT; } } if (newval && newlen) { len = newlen; if (len > table->maxlen) len = table->maxlen; if(copy_from_user(table->data, newval, len)) return -EFAULT; } } return 0;} /** * register_sysctl_table - register a sysctl hierarchy * @table: the top-level table structure * @insert_at_head: whether the entry should be inserted in front or at the end * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. An entry with a ctl_name of 0 terminates the table. * * The members of the &ctl_table structure are used as follows: * * ctl_name - This is the numeric sysctl value used by sysctl(2). The number * must be unique within that level of sysctl * * 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, and for sysctl(2) * * child - a pointer to the child sysctl table if this entry is a directory, or * %NULL. * * proc_handler - the text handler routine (described below) * * strategy - the strategy routine (described below) * * de - for internal use by the sysctl routines * * extra1, extra2 - extra pointers usable by the proc handler routines * * Leaf nodes in the sysctl tree will be represented by a single file * under /proc; non-leaf nodes will be represented by directories. * * sysctl(2) can automatically manage read and write requests through * the sysctl table. The data and maxlen fields of the ctl_table * struct enable minimal validation of the values being written to be * performed, and the mode field allows minimal authentication. * * More sophisticated management can be enabled by the provision of a * strategy routine with the table entry. This will be called before * any automatic read or write of the data is performed. * * The strategy routine may return * * < 0 - Error occurred (error is passed to user process) * * 0 - OK - proceed with automatic read or write. * * > 0 - OK - read or write has been done by the strategy routine, so * return immediately. * * There must be a proc_handler routine for any terminal nodes * mirrored under /proc/sys (non-terminals are handled by a built-in * directory handler). 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(ctl_table * table, int insert_at_head){ struct ctl_table_header *tmp; tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); if (!tmp) return NULL; tmp->ctl_table = table; INIT_LIST_HEAD(&tmp->ctl_entry); tmp->used = 0; tmp->unregistering = NULL; spin_lock(&sysctl_lock); if (insert_at_head) list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); else list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); spin_unlock(&sysctl_lock);#ifdef CONFIG_PROC_FS register_proc_table(table, proc_sys_root, tmp);#endif return tmp;} /** * unregister_sysctl_table - unregister a sysctl table hierarchy * @header: the header returned from 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(); spin_lock(&sysctl_lock); start_unregistering(header);#ifdef CONFIG_PROC_FS unregister_proc_table(header->ctl_table, proc_sys_root);#endif spin_unlock(&sysctl_lock); kfree(header);} /* * /proc/sys support */ #ifdef CONFIG_PROC_FS /* Scan the sysctl entries in table and add them all into /proc */static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set){ struct proc_dir_entry *de; int len; mode_t mode; for (; table->ctl_name; table++) { /* Can't do anything without a proc name. */ if (!table->procname) continue; /* Maybe we can't do anything with it... */ if (!table->proc_handler && !table->child) { printk(KERN_WARNING "SYSCTL: Can't register %s\n", table->procname); continue; } len = strlen(table->procname); mode = table->mode; de = NULL; if (table->proc_handler) mode |= S_IFREG; else { mode |= S_IFDIR; for (de = root->subdir; de; de = de->next) { if (proc_match(len, table->procname, de)) break; } /* If the subdir exists already, de is non-NULL */ } if (!de) { de = create_proc_entry(table->procname, mode, root); if (!de) continue; de->set = set; de->data = (void *) table; if (table->proc_handler) de->proc_fops = &proc_sys_file_operations; } table->de = de; if (de->mode & S_IFDIR) register_proc_table(table->child, de, set); }} /* * Unregister a /proc sysctl table and any subdirectories. */static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root){ struct proc_dir_entry *de; for (; table->ctl_name; table++) { if (!(de = table->de)) continue; if (de->mode & S_IFDIR) { if (!table->child) { printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); continue; } unregister_proc_table(table->child, de); /* Don't unregister directories which still have entries.. */ if (de->subdir) continue; } /* * In any case, mark the entry as goner; we'll keep it * around if it's busy, but we'll know to do nothing with * its fields. We are under sysctl_lock here. */ de->data = NULL; /* Don't unregister proc entries that are still being used.. */ if (atomic_read(&de->count)) continue; table->de = NULL; remove_proc_entry(table->procname, root); }} static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, size_t count, loff_t *ppos){ int op; struct proc_dir_entry *de = PDE(file->f_dentry->d_inode); struct ctl_table *table; size_t res; ssize_t error = -ENOTDIR; spin_lock(&sysctl_lock); if (de && de->data && use_table(de->set)) { /* * at that point we know that sysctl was not unregistered * and won't be until we finish */ spin_unlock(&sysctl_lock); table = (struct ctl_table *) de->data; if (!table || !table->proc_handler) goto out; error = -EPERM;Lines 1001–1500 of 2519. Previous lines Load more
.maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, #endif #ifdef CONFIG_MMU { .ctl_name = FS_LEASE_TIME, .procname = "lease-break-time", .data = &lease_break_time, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = FS_AIO_NR, .procname = "aio-nr", .data = &aio_nr, .maxlen = sizeof(aio_nr), .mode = 0444, .proc_handler = &proc_doulongvec_minmax, }, { .ctl_name = FS_AIO_MAX_NR, .procname = "aio-max-nr", .data = &aio_max_nr, .maxlen = sizeof(aio_max_nr), .mode = 0644, .proc_handler = &proc_doulongvec_minmax, }, #ifdef CONFIG_INOTIFY_USER { .ctl_name = FS_INOTIFY, .procname = "inotify", .mode = 0555, .child = inotify_table, }, #endif #endif { .ctl_name = KERN_SETUID_DUMPABLE, .procname = "suid_dumpable", .data = &suid_dumpable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = 0 } }; static ctl_table debug_table[] = { { .ctl_name = 0 } }; static ctl_table dev_table[] = { { .ctl_name = 0 } }; extern void init_irq_proc (void); static DEFINE_SPINLOCK(sysctl_lock); /* called under sysctl_lock */ static int use_table(struct ctl_table_header *p) { if (unlikely(p->unregistering)) return 0; p->used++; return 1; } /* called under sysctl_lock */ static void unuse_table(struct ctl_table_header *p) { if (!--p->used) if (unlikely(p->unregistering)) complete(p->unregistering); } /* called under sysctl_lock, will reacquire if has to wait */ static void start_unregistering(struct ctl_table_header *p) { /* * 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); spin_lock(&sysctl_lock); } /* * do not remove from the list until nobody holds it; walking the * list in do_sysctl() relies on that. */ list_del_init(&p->ctl_entry); } void __init sysctl_init(void) { #ifdef CONFIG_PROC_FS register_proc_table(root_table, proc_sys_root, &root_table_header); init_irq_proc(); #endif } int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen) { struct list_head *tmp; int error = -ENOTDIR; if (nlen <= 0 || nlen >= CTL_MAXNAME) return -ENOTDIR; if (oldval) { int old_len; if (!oldlenp || get_user(old_len, oldlenp)) return -EFAULT; } spin_lock(&sysctl_lock); tmp = &root_table_header.ctl_entry; do { struct ctl_table_header *head = list_entry(tmp, struct ctl_table_header, ctl_entry); void *context = NULL; if (!use_table(head)) continue; spin_unlock(&sysctl_lock); error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->ctl_table, &context); kfree(context); spin_lock(&sysctl_lock); unuse_table(head); if (error != -ENOTDIR) break; } while ((tmp = tmp->next) != &root_table_header.ctl_entry); spin_unlock(&sysctl_lock); return error; } asmlinkage long sys_sysctl(struct __sysctl_args __user *args) { struct __sysctl_args tmp; int error; if (copy_from_user(&tmp, args, sizeof(tmp))) return -EFAULT; lock_kernel(); error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, tmp.newval, tmp.newlen); unlock_kernel(); return error; } /* * ctl_perm does NOT grant the superuser all rights automatically, because * some sysctl variables are readonly even to root. */ static int test_perm(int mode, int op) { if (!current->euid) mode >>= 6; else if (in_egroup_p(0)) mode >>= 3; if ((mode & op & 0007) == op) return 0; return -EACCES; } static inline int ctl_perm(ctl_table *table, int op) { int error; error = security_sysctl(table, op); if (error) return error; return test_perm(table->mode, op); } static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, ctl_table *table, void **context) { int n; repeat: if (!nlen) return -ENOTDIR; if (get_user(n, name)) return -EFAULT; for ( ; table->ctl_name; table++) { if (n == table->ctl_name || table->ctl_name == CTL_ANY) { int error; if (table->child) { if (ctl_perm(table, 001)) return -EPERM; if (table->strategy) { error = table->strategy( table, name, nlen, oldval, oldlenp, newval, newlen, context); if (error) return error; } name++; nlen--; table = table->child; goto repeat; } error = do_sysctl_strategy(table, name, nlen, oldval, oldlenp, newval, newlen, context); return error; } } return -ENOTDIR; } /* Perform the actual read/write of a sysctl table entry. */ int do_sysctl_strategy (ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context) { int op = 0, rc; size_t len; if (oldval) op |= 004; if (newval) op |= 002; if (ctl_perm(table, op)) return -EPERM; if (table->strategy) { rc = table->strategy(table, name, nlen, oldval, oldlenp, newval, newlen, context); if (rc < 0) return rc; if (rc > 0) return 0; } /* If there is no strategy routine, or if the strategy returns * zero, proceed with automatic r/w */ if (table->data && table->maxlen) { if (oldval && oldlenp) { if (get_user(len, oldlenp)) return -EFAULT; if (len) { if (len > table->maxlen) len = table->maxlen; if(copy_to_user(oldval, table->data, len)) return -EFAULT; if(put_user(len, oldlenp)) return -EFAULT; } } if (newval && newlen) { len = newlen; if (len > table->maxlen) len = table->maxlen; if(copy_from_user(table->data, newval, len)) return -EFAULT; } } return 0; } /** * register_sysctl_table - register a sysctl hierarchy * @table: the top-level table structure * @insert_at_head: whether the entry should be inserted in front or at the end * * Register a sysctl table hierarchy. @table should be a filled in ctl_table * array. An entry with a ctl_name of 0 terminates the table. * * The members of the &ctl_table structure are used as follows: * * ctl_name - This is the numeric sysctl value used by sysctl(2). The number * must be unique within that level of sysctl * * 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, and for sysctl(2) * * child - a pointer to the child sysctl table if this entry is a directory, or * %NULL. * * proc_handler - the text handler routine (described below) * * strategy - the strategy routine (described below) * * de - for internal use by the sysctl routines * * extra1, extra2 - extra pointers usable by the proc handler routines * * Leaf nodes in the sysctl tree will be represented by a single file * under /proc; non-leaf nodes will be represented by directories. * * sysctl(2) can automatically manage read and write requests through * the sysctl table. The data and maxlen fields of the ctl_table * struct enable minimal validation of the values being written to be * performed, and the mode field allows minimal authentication. * * More sophisticated management can be enabled by the provision of a * strategy routine with the table entry. This will be called before * any automatic read or write of the data is performed. * * The strategy routine may return * * < 0 - Error occurred (error is passed to user process) * * 0 - OK - proceed with automatic read or write. * * > 0 - OK - read or write has been done by the strategy routine, so * return immediately. * * There must be a proc_handler routine for any terminal nodes * mirrored under /proc/sys (non-terminals are handled by a built-in * directory handler). 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(ctl_table * table, int insert_at_head) { struct ctl_table_header *tmp; tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); if (!tmp) return NULL; tmp->ctl_table = table; INIT_LIST_HEAD(&tmp->ctl_entry); tmp->used = 0; tmp->unregistering = NULL; spin_lock(&sysctl_lock); if (insert_at_head) list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); else list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); spin_unlock(&sysctl_lock); #ifdef CONFIG_PROC_FS register_proc_table(table, proc_sys_root, tmp); #endif return tmp; } /** * unregister_sysctl_table - unregister a sysctl table hierarchy * @header: the header returned from 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(); spin_lock(&sysctl_lock); start_unregistering(header); #ifdef CONFIG_PROC_FS unregister_proc_table(header->ctl_table, proc_sys_root); #endif spin_unlock(&sysctl_lock); kfree(header); } /* * /proc/sys support */ #ifdef CONFIG_PROC_FS /* Scan the sysctl entries in table and add them all into /proc */ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set) { struct proc_dir_entry *de; int len; mode_t mode; for (; table->ctl_name; table++) { /* Can't do anything without a proc name. */ if (!table->procname) continue; /* Maybe we can't do anything with it... */ if (!table->proc_handler && !table->child) { printk(KERN_WARNING "SYSCTL: Can't register %s\n", table->procname); continue; } len = strlen(table->procname); mode = table->mode; de = NULL; if (table->proc_handler) mode |= S_IFREG; else { mode |= S_IFDIR; for (de = root->subdir; de; de = de->next) { if (proc_match(len, table->procname, de)) break; } /* If the subdir exists already, de is non-NULL */ } if (!de) { de = create_proc_entry(table->procname, mode, root); if (!de) continue; de->set = set; de->data = (void *) table; if (table->proc_handler) de->proc_fops = &proc_sys_file_operations; } table->de = de; if (de->mode & S_IFDIR) register_proc_table(table->child, de, set); } } /* * Unregister a /proc sysctl table and any subdirectories. */ static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) { struct proc_dir_entry *de; for (; table->ctl_name; table++) { if (!(de = table->de)) continue; if (de->mode & S_IFDIR) { if (!table->child) { printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); continue; } unregister_proc_table(table->child, de); /* Don't unregister directories which still have entries.. */ if (de->subdir) continue; } /* * In any case, mark the entry as goner; we'll keep it * around if it's busy, but we'll know to do nothing with * its fields. We are under sysctl_lock here. */ de->data = NULL; /* Don't unregister proc entries that are still being used.. */ if (atomic_read(&de->count)) continue; table->de = NULL; remove_proc_entry(table->procname, root); } } static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, size_t count, loff_t *ppos) { int op; struct proc_dir_entry *de = PDE(file->f_dentry->d_inode); struct ctl_table *table; size_t res; ssize_t error = -ENOTDIR; spin_lock(&sysctl_lock); if (de && de->data && use_table(de->set)) { /* * at that point we know that sysctl was not unregistered * and won't be until we finish */ spin_unlock(&sysctl_lock); table = (struct ctl_table *) de->data; if (!table || !table->proc_handler) goto out; error = -EPERM;