2519 lines · 58.8 KB · C
RawDownload
		.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