xref: /openbmc/linux/fs/proc/proc_sysctl.c (revision e1675231)
177b14db5SEric W. Biederman /*
277b14db5SEric W. Biederman  * /proc/sys support
377b14db5SEric W. Biederman  */
477b14db5SEric W. Biederman 
577b14db5SEric W. Biederman #include <linux/sysctl.h>
677b14db5SEric W. Biederman #include <linux/proc_fs.h>
777b14db5SEric W. Biederman #include <linux/security.h>
877b14db5SEric W. Biederman #include "internal.h"
977b14db5SEric W. Biederman 
1077b14db5SEric W. Biederman static struct dentry_operations proc_sys_dentry_operations;
1177b14db5SEric W. Biederman static const struct file_operations proc_sys_file_operations;
1203a44825SJan Engelhardt static const struct inode_operations proc_sys_inode_operations;
139043476fSAl Viro static const struct file_operations proc_sys_dir_file_operations;
149043476fSAl Viro static const struct inode_operations proc_sys_dir_operations;
1577b14db5SEric W. Biederman 
169043476fSAl Viro static struct inode *proc_sys_make_inode(struct super_block *sb,
179043476fSAl Viro 		struct ctl_table_header *head, struct ctl_table *table)
1877b14db5SEric W. Biederman {
1977b14db5SEric W. Biederman 	struct inode *inode;
209043476fSAl Viro 	struct proc_inode *ei;
2177b14db5SEric W. Biederman 
229043476fSAl Viro 	inode = new_inode(sb);
2377b14db5SEric W. Biederman 	if (!inode)
2477b14db5SEric W. Biederman 		goto out;
2577b14db5SEric W. Biederman 
269043476fSAl Viro 	sysctl_head_get(head);
2777b14db5SEric W. Biederman 	ei = PROC_I(inode);
289043476fSAl Viro 	ei->sysctl = head;
299043476fSAl Viro 	ei->sysctl_entry = table;
309043476fSAl Viro 
3177b14db5SEric W. Biederman 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
329043476fSAl Viro 	inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
339043476fSAl Viro 	inode->i_mode = table->mode;
349043476fSAl Viro 	if (!table->child) {
359043476fSAl Viro 		inode->i_mode |= S_IFREG;
3677b14db5SEric W. Biederman 		inode->i_op = &proc_sys_inode_operations;
3777b14db5SEric W. Biederman 		inode->i_fop = &proc_sys_file_operations;
389043476fSAl Viro 	} else {
399043476fSAl Viro 		inode->i_mode |= S_IFDIR;
409043476fSAl Viro 		inode->i_nlink = 0;
419043476fSAl Viro 		inode->i_op = &proc_sys_dir_operations;
429043476fSAl Viro 		inode->i_fop = &proc_sys_dir_file_operations;
439043476fSAl Viro 	}
4477b14db5SEric W. Biederman out:
4577b14db5SEric W. Biederman 	return inode;
4677b14db5SEric W. Biederman }
4777b14db5SEric W. Biederman 
489043476fSAl Viro static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
4977b14db5SEric W. Biederman {
5077b14db5SEric W. Biederman 	int len;
519043476fSAl Viro 	for ( ; p->ctl_name || p->procname; p++) {
5277b14db5SEric W. Biederman 
539043476fSAl Viro 		if (!p->procname)
5477b14db5SEric W. Biederman 			continue;
5577b14db5SEric W. Biederman 
569043476fSAl Viro 		len = strlen(p->procname);
5777b14db5SEric W. Biederman 		if (len != name->len)
5877b14db5SEric W. Biederman 			continue;
5977b14db5SEric W. Biederman 
609043476fSAl Viro 		if (memcmp(p->procname, name->name, len) != 0)
6177b14db5SEric W. Biederman 			continue;
6277b14db5SEric W. Biederman 
6377b14db5SEric W. Biederman 		/* I have a match */
649043476fSAl Viro 		return p;
6577b14db5SEric W. Biederman 	}
6677b14db5SEric W. Biederman 	return NULL;
6777b14db5SEric W. Biederman }
6877b14db5SEric W. Biederman 
699043476fSAl Viro struct ctl_table_header *grab_header(struct inode *inode)
7077b14db5SEric W. Biederman {
719043476fSAl Viro 	if (PROC_I(inode)->sysctl)
729043476fSAl Viro 		return sysctl_head_grab(PROC_I(inode)->sysctl);
739043476fSAl Viro 	else
749043476fSAl Viro 		return sysctl_head_next(NULL);
7577b14db5SEric W. Biederman }
7677b14db5SEric W. Biederman 
7777b14db5SEric W. Biederman static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
7877b14db5SEric W. Biederman 					struct nameidata *nd)
7977b14db5SEric W. Biederman {
809043476fSAl Viro 	struct ctl_table_header *head = grab_header(dir);
819043476fSAl Viro 	struct ctl_table *table = PROC_I(dir)->sysctl_entry;
829043476fSAl Viro 	struct ctl_table_header *h = NULL;
839043476fSAl Viro 	struct qstr *name = &dentry->d_name;
849043476fSAl Viro 	struct ctl_table *p;
8577b14db5SEric W. Biederman 	struct inode *inode;
869043476fSAl Viro 	struct dentry *err = ERR_PTR(-ENOENT);
8777b14db5SEric W. Biederman 
889043476fSAl Viro 	if (IS_ERR(head))
899043476fSAl Viro 		return ERR_CAST(head);
909043476fSAl Viro 
919043476fSAl Viro 	if (table && !table->child) {
929043476fSAl Viro 		WARN_ON(1);
939043476fSAl Viro 		goto out;
949043476fSAl Viro 	}
959043476fSAl Viro 
969043476fSAl Viro 	table = table ? table->child : head->ctl_table;
979043476fSAl Viro 
989043476fSAl Viro 	p = find_in_table(table, name);
999043476fSAl Viro 	if (!p) {
1009043476fSAl Viro 		for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
1019043476fSAl Viro 			if (h->attached_to != table)
1029043476fSAl Viro 				continue;
1039043476fSAl Viro 			p = find_in_table(h->attached_by, name);
1049043476fSAl Viro 			if (p)
1059043476fSAl Viro 				break;
1069043476fSAl Viro 		}
1079043476fSAl Viro 	}
1089043476fSAl Viro 
1099043476fSAl Viro 	if (!p)
11077b14db5SEric W. Biederman 		goto out;
11177b14db5SEric W. Biederman 
11277b14db5SEric W. Biederman 	err = ERR_PTR(-ENOMEM);
1139043476fSAl Viro 	inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
1149043476fSAl Viro 	if (h)
1159043476fSAl Viro 		sysctl_head_finish(h);
1169043476fSAl Viro 
11777b14db5SEric W. Biederman 	if (!inode)
11877b14db5SEric W. Biederman 		goto out;
11977b14db5SEric W. Biederman 
12077b14db5SEric W. Biederman 	err = NULL;
12177b14db5SEric W. Biederman 	dentry->d_op = &proc_sys_dentry_operations;
12277b14db5SEric W. Biederman 	d_add(dentry, inode);
12377b14db5SEric W. Biederman 
12477b14db5SEric W. Biederman out:
12577b14db5SEric W. Biederman 	sysctl_head_finish(head);
12677b14db5SEric W. Biederman 	return err;
12777b14db5SEric W. Biederman }
12877b14db5SEric W. Biederman 
1297708bfb1SPavel Emelyanov static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
1307708bfb1SPavel Emelyanov 		size_t count, loff_t *ppos, int write)
13177b14db5SEric W. Biederman {
1329043476fSAl Viro 	struct inode *inode = filp->f_path.dentry->d_inode;
1339043476fSAl Viro 	struct ctl_table_header *head = grab_header(inode);
1349043476fSAl Viro 	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
1352a2da53bSDavid Howells 	ssize_t error;
1362a2da53bSDavid Howells 	size_t res;
13777b14db5SEric W. Biederman 
1389043476fSAl Viro 	if (IS_ERR(head))
1399043476fSAl Viro 		return PTR_ERR(head);
14077b14db5SEric W. Biederman 
14177b14db5SEric W. Biederman 	/*
14277b14db5SEric W. Biederman 	 * At this point we know that the sysctl was not unregistered
14377b14db5SEric W. Biederman 	 * and won't be until we finish.
14477b14db5SEric W. Biederman 	 */
14577b14db5SEric W. Biederman 	error = -EPERM;
146d7321cd6SPavel Emelyanov 	if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ))
14777b14db5SEric W. Biederman 		goto out;
14877b14db5SEric W. Biederman 
1499043476fSAl Viro 	/* if that can happen at all, it should be -EINVAL, not -EISDIR */
1509043476fSAl Viro 	error = -EINVAL;
1519043476fSAl Viro 	if (!table->proc_handler)
1529043476fSAl Viro 		goto out;
1539043476fSAl Viro 
15477b14db5SEric W. Biederman 	/* careful: calling conventions are nasty here */
15577b14db5SEric W. Biederman 	res = count;
1567708bfb1SPavel Emelyanov 	error = table->proc_handler(table, write, filp, buf, &res, ppos);
15777b14db5SEric W. Biederman 	if (!error)
15877b14db5SEric W. Biederman 		error = res;
15977b14db5SEric W. Biederman out:
16077b14db5SEric W. Biederman 	sysctl_head_finish(head);
16177b14db5SEric W. Biederman 
16277b14db5SEric W. Biederman 	return error;
16377b14db5SEric W. Biederman }
16477b14db5SEric W. Biederman 
1657708bfb1SPavel Emelyanov static ssize_t proc_sys_read(struct file *filp, char __user *buf,
1667708bfb1SPavel Emelyanov 				size_t count, loff_t *ppos)
1677708bfb1SPavel Emelyanov {
1687708bfb1SPavel Emelyanov 	return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0);
1697708bfb1SPavel Emelyanov }
1707708bfb1SPavel Emelyanov 
17177b14db5SEric W. Biederman static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
17277b14db5SEric W. Biederman 				size_t count, loff_t *ppos)
17377b14db5SEric W. Biederman {
1747708bfb1SPavel Emelyanov 	return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
17577b14db5SEric W. Biederman }
17677b14db5SEric W. Biederman 
17777b14db5SEric W. Biederman 
17877b14db5SEric W. Biederman static int proc_sys_fill_cache(struct file *filp, void *dirent,
1799043476fSAl Viro 				filldir_t filldir,
1809043476fSAl Viro 				struct ctl_table_header *head,
1819043476fSAl Viro 				struct ctl_table *table)
18277b14db5SEric W. Biederman {
18377b14db5SEric W. Biederman 	struct dentry *child, *dir = filp->f_path.dentry;
18477b14db5SEric W. Biederman 	struct inode *inode;
18577b14db5SEric W. Biederman 	struct qstr qname;
18677b14db5SEric W. Biederman 	ino_t ino = 0;
18777b14db5SEric W. Biederman 	unsigned type = DT_UNKNOWN;
18877b14db5SEric W. Biederman 
18977b14db5SEric W. Biederman 	qname.name = table->procname;
19077b14db5SEric W. Biederman 	qname.len  = strlen(table->procname);
19177b14db5SEric W. Biederman 	qname.hash = full_name_hash(qname.name, qname.len);
19277b14db5SEric W. Biederman 
19377b14db5SEric W. Biederman 	child = d_lookup(dir, &qname);
19477b14db5SEric W. Biederman 	if (!child) {
1959043476fSAl Viro 		child = d_alloc(dir, &qname);
1969043476fSAl Viro 		if (child) {
1979043476fSAl Viro 			inode = proc_sys_make_inode(dir->d_sb, head, table);
1989043476fSAl Viro 			if (!inode) {
1999043476fSAl Viro 				dput(child);
2009043476fSAl Viro 				return -ENOMEM;
2019043476fSAl Viro 			} else {
2029043476fSAl Viro 				child->d_op = &proc_sys_dentry_operations;
2039043476fSAl Viro 				d_add(child, inode);
20477b14db5SEric W. Biederman 			}
2059043476fSAl Viro 		} else {
2069043476fSAl Viro 			return -ENOMEM;
20777b14db5SEric W. Biederman 		}
20877b14db5SEric W. Biederman 	}
20977b14db5SEric W. Biederman 	inode = child->d_inode;
21077b14db5SEric W. Biederman 	ino  = inode->i_ino;
21177b14db5SEric W. Biederman 	type = inode->i_mode >> 12;
21277b14db5SEric W. Biederman 	dput(child);
2139043476fSAl Viro 	return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
2149043476fSAl Viro }
2159043476fSAl Viro 
2169043476fSAl Viro static int scan(struct ctl_table_header *head, ctl_table *table,
2179043476fSAl Viro 		unsigned long *pos, struct file *file,
2189043476fSAl Viro 		void *dirent, filldir_t filldir)
2199043476fSAl Viro {
2209043476fSAl Viro 
2219043476fSAl Viro 	for (; table->ctl_name || table->procname; table++, (*pos)++) {
2229043476fSAl Viro 		int res;
2239043476fSAl Viro 
2249043476fSAl Viro 		/* Can't do anything without a proc name */
2259043476fSAl Viro 		if (!table->procname)
2269043476fSAl Viro 			continue;
2279043476fSAl Viro 
2289043476fSAl Viro 		if (*pos < file->f_pos)
2299043476fSAl Viro 			continue;
2309043476fSAl Viro 
2319043476fSAl Viro 		res = proc_sys_fill_cache(file, dirent, filldir, head, table);
2329043476fSAl Viro 		if (res)
2339043476fSAl Viro 			return res;
2349043476fSAl Viro 
2359043476fSAl Viro 		file->f_pos = *pos + 1;
2369043476fSAl Viro 	}
2379043476fSAl Viro 	return 0;
23877b14db5SEric W. Biederman }
23977b14db5SEric W. Biederman 
24077b14db5SEric W. Biederman static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
24177b14db5SEric W. Biederman {
2429043476fSAl Viro 	struct dentry *dentry = filp->f_path.dentry;
24377b14db5SEric W. Biederman 	struct inode *inode = dentry->d_inode;
2449043476fSAl Viro 	struct ctl_table_header *head = grab_header(inode);
2459043476fSAl Viro 	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
2469043476fSAl Viro 	struct ctl_table_header *h = NULL;
24777b14db5SEric W. Biederman 	unsigned long pos;
2489043476fSAl Viro 	int ret = -EINVAL;
24977b14db5SEric W. Biederman 
2509043476fSAl Viro 	if (IS_ERR(head))
2519043476fSAl Viro 		return PTR_ERR(head);
2529043476fSAl Viro 
2539043476fSAl Viro 	if (table && !table->child) {
2549043476fSAl Viro 		WARN_ON(1);
25577b14db5SEric W. Biederman 		goto out;
2569043476fSAl Viro 	}
2579043476fSAl Viro 
2589043476fSAl Viro 	table = table ? table->child : head->ctl_table;
25977b14db5SEric W. Biederman 
26077b14db5SEric W. Biederman 	ret = 0;
26177b14db5SEric W. Biederman 	/* Avoid a switch here: arm builds fail with missing __cmpdi2 */
26277b14db5SEric W. Biederman 	if (filp->f_pos == 0) {
26377b14db5SEric W. Biederman 		if (filldir(dirent, ".", 1, filp->f_pos,
26477b14db5SEric W. Biederman 				inode->i_ino, DT_DIR) < 0)
26577b14db5SEric W. Biederman 			goto out;
26677b14db5SEric W. Biederman 		filp->f_pos++;
26777b14db5SEric W. Biederman 	}
26877b14db5SEric W. Biederman 	if (filp->f_pos == 1) {
26977b14db5SEric W. Biederman 		if (filldir(dirent, "..", 2, filp->f_pos,
27077b14db5SEric W. Biederman 				parent_ino(dentry), DT_DIR) < 0)
27177b14db5SEric W. Biederman 			goto out;
27277b14db5SEric W. Biederman 		filp->f_pos++;
27377b14db5SEric W. Biederman 	}
27477b14db5SEric W. Biederman 	pos = 2;
27577b14db5SEric W. Biederman 
2769043476fSAl Viro 	ret = scan(head, table, &pos, filp, dirent, filldir);
2779043476fSAl Viro 	if (ret)
27877b14db5SEric W. Biederman 		goto out;
2799043476fSAl Viro 
2809043476fSAl Viro 	for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
2819043476fSAl Viro 		if (h->attached_to != table)
2829043476fSAl Viro 			continue;
2839043476fSAl Viro 		ret = scan(h, h->attached_by, &pos, filp, dirent, filldir);
2849043476fSAl Viro 		if (ret) {
2859043476fSAl Viro 			sysctl_head_finish(h);
2869043476fSAl Viro 			break;
28777b14db5SEric W. Biederman 		}
28877b14db5SEric W. Biederman 	}
28977b14db5SEric W. Biederman 	ret = 1;
29077b14db5SEric W. Biederman out:
29177b14db5SEric W. Biederman 	sysctl_head_finish(head);
29277b14db5SEric W. Biederman 	return ret;
29377b14db5SEric W. Biederman }
29477b14db5SEric W. Biederman 
295e6305c43SAl Viro static int proc_sys_permission(struct inode *inode, int mask)
29677b14db5SEric W. Biederman {
29777b14db5SEric W. Biederman 	/*
29877b14db5SEric W. Biederman 	 * sysctl entries that are not writeable,
29977b14db5SEric W. Biederman 	 * are _NOT_ writeable, capabilities or not.
30077b14db5SEric W. Biederman 	 */
3019043476fSAl Viro 	struct ctl_table_header *head = grab_header(inode);
3029043476fSAl Viro 	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
30377b14db5SEric W. Biederman 	int error;
30477b14db5SEric W. Biederman 
3059043476fSAl Viro 	if (IS_ERR(head))
3069043476fSAl Viro 		return PTR_ERR(head);
30777b14db5SEric W. Biederman 
3089043476fSAl Viro 	if (!table) /* global root - r-xr-xr-x */
3099043476fSAl Viro 		error = mask & MAY_WRITE ? -EACCES : 0;
3109043476fSAl Viro 	else /* Use the permissions on the sysctl table entry */
311d7321cd6SPavel Emelyanov 		error = sysctl_perm(head->root, table, mask);
3129043476fSAl Viro 
31377b14db5SEric W. Biederman 	sysctl_head_finish(head);
31477b14db5SEric W. Biederman 	return error;
31577b14db5SEric W. Biederman }
31677b14db5SEric W. Biederman 
31777b14db5SEric W. Biederman static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
31877b14db5SEric W. Biederman {
31977b14db5SEric W. Biederman 	struct inode *inode = dentry->d_inode;
32077b14db5SEric W. Biederman 	int error;
32177b14db5SEric W. Biederman 
32277b14db5SEric W. Biederman 	if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
32377b14db5SEric W. Biederman 		return -EPERM;
32477b14db5SEric W. Biederman 
32577b14db5SEric W. Biederman 	error = inode_change_ok(inode, attr);
32677b14db5SEric W. Biederman 	if (!error)
32777b14db5SEric W. Biederman 		error = inode_setattr(inode, attr);
32877b14db5SEric W. Biederman 
32977b14db5SEric W. Biederman 	return error;
33077b14db5SEric W. Biederman }
33177b14db5SEric W. Biederman 
3329043476fSAl Viro static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
3339043476fSAl Viro {
3349043476fSAl Viro 	struct inode *inode = dentry->d_inode;
3359043476fSAl Viro 	struct ctl_table_header *head = grab_header(inode);
3369043476fSAl Viro 	struct ctl_table *table = PROC_I(inode)->sysctl_entry;
3379043476fSAl Viro 
3389043476fSAl Viro 	if (IS_ERR(head))
3399043476fSAl Viro 		return PTR_ERR(head);
3409043476fSAl Viro 
3419043476fSAl Viro 	generic_fillattr(inode, stat);
3429043476fSAl Viro 	if (table)
3439043476fSAl Viro 		stat->mode = (stat->mode & S_IFMT) | table->mode;
3449043476fSAl Viro 
3459043476fSAl Viro 	sysctl_head_finish(head);
3469043476fSAl Viro 	return 0;
3479043476fSAl Viro }
3489043476fSAl Viro 
34977b14db5SEric W. Biederman static const struct file_operations proc_sys_file_operations = {
35077b14db5SEric W. Biederman 	.read		= proc_sys_read,
35177b14db5SEric W. Biederman 	.write		= proc_sys_write,
3529043476fSAl Viro };
3539043476fSAl Viro 
3549043476fSAl Viro static const struct file_operations proc_sys_dir_file_operations = {
35577b14db5SEric W. Biederman 	.readdir	= proc_sys_readdir,
35677b14db5SEric W. Biederman };
35777b14db5SEric W. Biederman 
35803a44825SJan Engelhardt static const struct inode_operations proc_sys_inode_operations = {
3599043476fSAl Viro 	.permission	= proc_sys_permission,
3609043476fSAl Viro 	.setattr	= proc_sys_setattr,
3619043476fSAl Viro 	.getattr	= proc_sys_getattr,
3629043476fSAl Viro };
3639043476fSAl Viro 
3649043476fSAl Viro static const struct inode_operations proc_sys_dir_operations = {
36577b14db5SEric W. Biederman 	.lookup		= proc_sys_lookup,
36677b14db5SEric W. Biederman 	.permission	= proc_sys_permission,
36777b14db5SEric W. Biederman 	.setattr	= proc_sys_setattr,
3689043476fSAl Viro 	.getattr	= proc_sys_getattr,
36977b14db5SEric W. Biederman };
37077b14db5SEric W. Biederman 
37177b14db5SEric W. Biederman static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
37277b14db5SEric W. Biederman {
3739043476fSAl Viro 	return !PROC_I(dentry->d_inode)->sysctl->unregistering;
3749043476fSAl Viro }
3759043476fSAl Viro 
3769043476fSAl Viro static int proc_sys_delete(struct dentry *dentry)
3779043476fSAl Viro {
3789043476fSAl Viro 	return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
3799043476fSAl Viro }
3809043476fSAl Viro 
3819043476fSAl Viro static int proc_sys_compare(struct dentry *dir, struct qstr *qstr,
3829043476fSAl Viro 			    struct qstr *name)
3839043476fSAl Viro {
3849043476fSAl Viro 	struct dentry *dentry = container_of(qstr, struct dentry, d_name);
3859043476fSAl Viro 	if (qstr->len != name->len)
3869043476fSAl Viro 		return 1;
3879043476fSAl Viro 	if (memcmp(qstr->name, name->name, name->len))
3889043476fSAl Viro 		return 1;
3899043476fSAl Viro 	return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl);
39077b14db5SEric W. Biederman }
39177b14db5SEric W. Biederman 
39277b14db5SEric W. Biederman static struct dentry_operations proc_sys_dentry_operations = {
39377b14db5SEric W. Biederman 	.d_revalidate	= proc_sys_revalidate,
3949043476fSAl Viro 	.d_delete	= proc_sys_delete,
3959043476fSAl Viro 	.d_compare	= proc_sys_compare,
39677b14db5SEric W. Biederman };
39777b14db5SEric W. Biederman 
39877b14db5SEric W. Biederman int proc_sys_init(void)
39977b14db5SEric W. Biederman {
400e1675231SAlexey Dobriyan 	struct proc_dir_entry *proc_sys_root;
401e1675231SAlexey Dobriyan 
40277b14db5SEric W. Biederman 	proc_sys_root = proc_mkdir("sys", NULL);
4039043476fSAl Viro 	proc_sys_root->proc_iops = &proc_sys_dir_operations;
4049043476fSAl Viro 	proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
40577b14db5SEric W. Biederman 	proc_sys_root->nlink = 0;
40677b14db5SEric W. Biederman 	return 0;
40777b14db5SEric W. Biederman }
408