• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * /proc/uid support
3  */
4 
5 #include <linux/cpufreq_times.h>
6 #include <linux/fs.h>
7 #include <linux/hashtable.h>
8 #include <linux/init.h>
9 #include <linux/proc_fs.h>
10 #include <linux/rtmutex.h>
11 #include <linux/sched.h>
12 #include <linux/seq_file.h>
13 #include <linux/slab.h>
14 #include "internal.h"
15 
16 static struct proc_dir_entry *proc_uid;
17 
18 #define UID_HASH_BITS 10
19 
20 static DECLARE_HASHTABLE(proc_uid_hash_table, UID_HASH_BITS);
21 
22 /*
23  * use rt_mutex here to avoid priority inversion between high-priority readers
24  * of these files and tasks calling proc_register_uid().
25  */
26 static DEFINE_RT_MUTEX(proc_uid_lock); /* proc_uid_hash_table */
27 
28 struct uid_hash_entry {
29 	uid_t uid;
30 	struct hlist_node hash;
31 };
32 
33 /* Caller must hold proc_uid_lock */
uid_hash_entry_exists_locked(uid_t uid)34 static bool uid_hash_entry_exists_locked(uid_t uid)
35 {
36 	struct uid_hash_entry *entry;
37 
38 	hash_for_each_possible(proc_uid_hash_table, entry, hash, uid) {
39 		if (entry->uid == uid)
40 			return true;
41 	}
42 	return false;
43 }
44 
proc_register_uid(kuid_t kuid)45 void proc_register_uid(kuid_t kuid)
46 {
47 	struct uid_hash_entry *entry;
48 	bool exists;
49 	uid_t uid = from_kuid_munged(current_user_ns(), kuid);
50 
51 	rt_mutex_lock(&proc_uid_lock);
52 	exists = uid_hash_entry_exists_locked(uid);
53 	rt_mutex_unlock(&proc_uid_lock);
54 	if (exists)
55 		return;
56 
57 	entry = kzalloc(sizeof(struct uid_hash_entry), GFP_KERNEL);
58 	if (!entry)
59 		return;
60 	entry->uid = uid;
61 
62 	rt_mutex_lock(&proc_uid_lock);
63 	if (uid_hash_entry_exists_locked(uid))
64 		kfree(entry);
65 	else
66 		hash_add(proc_uid_hash_table, &entry->hash, uid);
67 	rt_mutex_unlock(&proc_uid_lock);
68 }
69 
70 struct uid_entry {
71 	const char *name;
72 	int len;
73 	umode_t mode;
74 	const struct inode_operations *iop;
75 	const struct file_operations *fop;
76 };
77 
78 #define NOD(NAME, MODE, IOP, FOP) {			\
79 	.name	= (NAME),				\
80 	.len	= sizeof(NAME) - 1,			\
81 	.mode	= MODE,					\
82 	.iop	= IOP,					\
83 	.fop	= FOP,					\
84 }
85 
86 #ifdef CONFIG_CPU_FREQ_TIMES
87 static const struct file_operations proc_uid_time_in_state_operations = {
88 	.open		= single_uid_time_in_state_open,
89 	.read		= seq_read,
90 	.llseek		= seq_lseek,
91 	.release	= single_release,
92 };
93 #endif
94 
95 static const struct uid_entry uid_base_stuff[] = {
96 #ifdef CONFIG_CPU_FREQ_TIMES
97 	NOD("time_in_state", 0444, NULL, &proc_uid_time_in_state_operations),
98 #endif
99 };
100 
101 static const struct inode_operations proc_uid_def_inode_operations = {
102 	.setattr	= proc_setattr,
103 };
104 
proc_uid_make_inode(struct super_block * sb,kuid_t kuid)105 static struct inode *proc_uid_make_inode(struct super_block *sb, kuid_t kuid)
106 {
107 	struct inode *inode;
108 
109 	inode = new_inode(sb);
110 	if (!inode)
111 		return NULL;
112 
113 	inode->i_ino = get_next_ino();
114 	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
115 	inode->i_op = &proc_uid_def_inode_operations;
116 	inode->i_uid = kuid;
117 
118 	return inode;
119 }
120 
proc_uident_instantiate(struct dentry * dentry,struct task_struct * unused,const void * ptr)121 static struct dentry *proc_uident_instantiate(struct dentry *dentry,
122 				   struct task_struct *unused, const void *ptr)
123 {
124 	const struct uid_entry *u = ptr;
125 	struct inode *inode;
126 
127 	uid_t uid = name_to_int(&dentry->d_name);
128 	kuid_t kuid;
129 	bool uid_exists;
130 	rt_mutex_lock(&proc_uid_lock);
131 	uid_exists = uid_hash_entry_exists_locked(uid);
132 	rt_mutex_unlock(&proc_uid_lock);
133 	if (uid_exists) {
134 		kuid = make_kuid(current_user_ns(), uid);
135 		inode = proc_uid_make_inode(dentry->d_sb, kuid);
136 		if (!inode)
137 			return ERR_PTR(-ENOENT);
138 	} else {
139 		return ERR_PTR(-ENOENT);
140 	}
141 
142 	inode->i_mode = u->mode;
143 	if (S_ISDIR(inode->i_mode))
144 		set_nlink(inode, 2);
145 	if (u->iop)
146 		inode->i_op = u->iop;
147 	if (u->fop)
148 		inode->i_fop = u->fop;
149 
150 	return d_splice_alias(inode, dentry);
151 }
152 
proc_uid_base_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)153 static struct dentry *proc_uid_base_lookup(struct inode *dir,
154 					   struct dentry *dentry,
155 					   unsigned int flags)
156 {
157 	const struct uid_entry *u, *last;
158 	unsigned int nents = ARRAY_SIZE(uid_base_stuff);
159 
160 	if (nents == 0)
161 		return ERR_PTR(-ENOENT);
162 
163 	last = &uid_base_stuff[nents - 1];
164 	for (u = uid_base_stuff; u <= last; u++) {
165 		if (u->len != dentry->d_name.len)
166 			continue;
167 		if (!memcmp(dentry->d_name.name, u->name, u->len))
168 			break;
169 	}
170 	if (u > last)
171 		return ERR_PTR(-ENOENT);
172 
173 	return proc_uident_instantiate(dentry, NULL, u);
174 }
175 
proc_uid_base_readdir(struct file * file,struct dir_context * ctx)176 static int proc_uid_base_readdir(struct file *file, struct dir_context *ctx)
177 {
178 	unsigned int nents = ARRAY_SIZE(uid_base_stuff);
179 	const struct uid_entry *u;
180 
181 	if (!dir_emit_dots(file, ctx))
182 		return 0;
183 
184 	if (ctx->pos >= nents + 2)
185 		return 0;
186 
187 	for (u = uid_base_stuff + (ctx->pos - 2);
188 	     u < uid_base_stuff + nents; u++) {
189 		if (!proc_fill_cache(file, ctx, u->name, u->len,
190 				     proc_uident_instantiate, NULL, u))
191 			break;
192 		ctx->pos++;
193 	}
194 
195 	return 0;
196 }
197 
198 static const struct inode_operations proc_uid_base_inode_operations = {
199 	.lookup		= proc_uid_base_lookup,
200 	.setattr	= proc_setattr,
201 };
202 
203 static const struct file_operations proc_uid_base_operations = {
204 	.read		= generic_read_dir,
205 	.iterate	= proc_uid_base_readdir,
206 	.llseek		= default_llseek,
207 };
208 
proc_uid_instantiate(struct dentry * dentry,struct task_struct * unused,const void * ptr)209 static struct dentry *proc_uid_instantiate(struct dentry *dentry,
210 				struct task_struct *unused, const void *ptr)
211 {
212 	unsigned int i, len;
213 	nlink_t nlinks;
214 	kuid_t *kuid = (kuid_t *)ptr;
215 	struct inode *inode = proc_uid_make_inode(dentry->d_sb, *kuid);
216 
217 	if (!inode)
218 		return ERR_PTR(-ENOENT);
219 
220 	inode->i_mode = S_IFDIR | 0555;
221 	inode->i_op = &proc_uid_base_inode_operations;
222 	inode->i_fop = &proc_uid_base_operations;
223 	inode->i_flags |= S_IMMUTABLE;
224 
225 	nlinks = 2;
226 	len = ARRAY_SIZE(uid_base_stuff);
227 	for (i = 0; i < len; ++i) {
228 		if (S_ISDIR(uid_base_stuff[i].mode))
229 			++nlinks;
230 	}
231 	set_nlink(inode, nlinks);
232 
233 	return d_splice_alias(inode, dentry);
234 }
235 
proc_uid_readdir(struct file * file,struct dir_context * ctx)236 static int proc_uid_readdir(struct file *file, struct dir_context *ctx)
237 {
238 	int last_shown, i;
239 	unsigned long bkt;
240 	struct uid_hash_entry *entry;
241 
242 	if (!dir_emit_dots(file, ctx))
243 		return 0;
244 
245 	i = 0;
246 	last_shown = ctx->pos - 2;
247 	rt_mutex_lock(&proc_uid_lock);
248 	hash_for_each(proc_uid_hash_table, bkt, entry, hash) {
249 		int len;
250 		char buf[PROC_NUMBUF];
251 
252 		if (i < last_shown)
253 			continue;
254 		len = snprintf(buf, sizeof(buf), "%u", entry->uid);
255 		if (!proc_fill_cache(file, ctx, buf, len,
256 				     proc_uid_instantiate, NULL, &entry->uid))
257 			break;
258 		i++;
259 		ctx->pos++;
260 	}
261 	rt_mutex_unlock(&proc_uid_lock);
262 	return 0;
263 }
264 
proc_uid_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)265 static struct dentry *proc_uid_lookup(struct inode *dir, struct dentry *dentry,
266 				      unsigned int flags)
267 {
268 	int result = -ENOENT;
269 
270 	uid_t uid = name_to_int(&dentry->d_name);
271 	bool uid_exists;
272 
273 	rt_mutex_lock(&proc_uid_lock);
274 	uid_exists = uid_hash_entry_exists_locked(uid);
275 	rt_mutex_unlock(&proc_uid_lock);
276 	if (uid_exists) {
277 		kuid_t kuid = make_kuid(current_user_ns(), uid);
278 
279 		return proc_uid_instantiate(dentry, NULL, &kuid);
280 	}
281 	return ERR_PTR(result);
282 }
283 
284 static const struct file_operations proc_uid_operations = {
285 	.read		= generic_read_dir,
286 	.iterate	= proc_uid_readdir,
287 	.llseek		= default_llseek,
288 };
289 
290 static const struct inode_operations proc_uid_inode_operations = {
291 	.lookup		= proc_uid_lookup,
292 	.setattr	= proc_setattr,
293 };
294 
proc_uid_init(void)295 int __init proc_uid_init(void)
296 {
297 	proc_uid = proc_mkdir("uid", NULL);
298 	if (!proc_uid)
299 		return -ENOMEM;
300 	proc_uid->proc_iops = &proc_uid_inode_operations;
301 	proc_uid->proc_fops = &proc_uid_operations;
302 
303 	return 0;
304 }
305