Skip to content

Commit 7b44ab9

Browse files
committed
userns: Disassociate user_struct from the user_namespace.
Modify alloc_uid to take a kuid and make the user hash table global. Stop holding a reference to the user namespace in struct user_struct. This simplifies the code and makes the per user accounting not care about which user namespace a uid happens to appear in. Acked-by: Serge Hallyn <[email protected]> Signed-off-by: Eric W. Biederman <[email protected]>
1 parent 5673a94 commit 7b44ab9

File tree

6 files changed

+55
-43
lines changed

6 files changed

+55
-43
lines changed

fs/ioprio.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
6565
struct task_struct *p, *g;
6666
struct user_struct *user;
6767
struct pid *pgrp;
68+
kuid_t uid;
6869
int ret;
6970

7071
switch (class) {
@@ -110,16 +111,21 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
110111
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
111112
break;
112113
case IOPRIO_WHO_USER:
114+
uid = make_kuid(current_user_ns(), who);
115+
if (!uid_valid(uid))
116+
break;
113117
if (!who)
114118
user = current_user();
115119
else
116-
user = find_user(who);
120+
user = find_user(uid);
117121

118122
if (!user)
119123
break;
120124

121125
do_each_thread(g, p) {
122-
if (__task_cred(p)->uid != who)
126+
const struct cred *tcred = __task_cred(p);
127+
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
128+
if (!uid_eq(tcred_uid, uid))
123129
continue;
124130
ret = set_task_ioprio(p, ioprio);
125131
if (ret)
@@ -174,6 +180,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
174180
struct task_struct *g, *p;
175181
struct user_struct *user;
176182
struct pid *pgrp;
183+
kuid_t uid;
177184
int ret = -ESRCH;
178185
int tmpio;
179186

@@ -203,16 +210,19 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
203210
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
204211
break;
205212
case IOPRIO_WHO_USER:
213+
uid = make_kuid(current_user_ns(), who);
206214
if (!who)
207215
user = current_user();
208216
else
209-
user = find_user(who);
217+
user = find_user(uid);
210218

211219
if (!user)
212220
break;
213221

214222
do_each_thread(g, p) {
215-
if (__task_cred(p)->uid != user->uid)
223+
const struct cred *tcred = __task_cred(p);
224+
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
225+
if (!uid_eq(tcred_uid, user->uid))
216226
continue;
217227
tmpio = get_task_ioprio(p);
218228
if (tmpio < 0)

include/linux/sched.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct sched_param {
9090
#include <linux/latencytop.h>
9191
#include <linux/cred.h>
9292
#include <linux/llist.h>
93+
#include <linux/uidgid.h>
9394

9495
#include <asm/processor.h>
9596

@@ -728,8 +729,7 @@ struct user_struct {
728729

729730
/* Hash table maintenance information */
730731
struct hlist_node uidhash_node;
731-
uid_t uid;
732-
struct user_namespace *_user_ns; /* Don't use will be removed soon */
732+
kuid_t uid;
733733

734734
#ifdef CONFIG_PERF_EVENTS
735735
atomic_long_t locked_vm;
@@ -738,7 +738,7 @@ struct user_struct {
738738

739739
extern int uids_sysfs_init(void);
740740

741-
extern struct user_struct *find_user(uid_t);
741+
extern struct user_struct *find_user(kuid_t);
742742

743743
extern struct user_struct root_user;
744744
#define INIT_USER (&root_user)
@@ -2177,7 +2177,7 @@ extern struct task_struct *find_task_by_pid_ns(pid_t nr,
21772177
extern void __set_special_pids(struct pid *pid);
21782178

21792179
/* per-UID process charging. */
2180-
extern struct user_struct * alloc_uid(struct user_namespace *, uid_t);
2180+
extern struct user_struct * alloc_uid(kuid_t);
21812181
static inline struct user_struct *get_uid(struct user_struct *u)
21822182
{
21832183
atomic_inc(&u->__count);

include/linux/user_namespace.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,8 @@
66
#include <linux/sched.h>
77
#include <linux/err.h>
88

9-
#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7)
10-
#define UIDHASH_SZ (1 << UIDHASH_BITS)
11-
129
struct user_namespace {
1310
struct kref kref;
14-
struct hlist_head uidhash_table[UIDHASH_SZ];
1511
struct user_namespace *parent;
1612
struct user_struct *creator;
1713
struct work_struct destroyer;

kernel/sys.c

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
175175
const struct cred *cred = current_cred();
176176
int error = -EINVAL;
177177
struct pid *pgrp;
178+
kuid_t cred_uid;
179+
kuid_t uid;
178180

179181
if (which > PRIO_USER || which < PRIO_PROCESS)
180182
goto out;
@@ -207,18 +209,22 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
207209
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
208210
break;
209211
case PRIO_USER:
212+
cred_uid = make_kuid(cred->user_ns, cred->uid);
213+
uid = make_kuid(cred->user_ns, who);
210214
user = cred->user;
211215
if (!who)
212-
who = cred->uid;
213-
else if ((who != cred->uid) &&
214-
!(user = find_user(who)))
216+
uid = cred_uid;
217+
else if (!uid_eq(uid, cred_uid) &&
218+
!(user = find_user(uid)))
215219
goto out_unlock; /* No processes for this user */
216220

217221
do_each_thread(g, p) {
218-
if (__task_cred(p)->uid == who)
222+
const struct cred *tcred = __task_cred(p);
223+
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
224+
if (uid_eq(tcred_uid, uid))
219225
error = set_one_prio(p, niceval, error);
220226
} while_each_thread(g, p);
221-
if (who != cred->uid)
227+
if (!uid_eq(uid, cred_uid))
222228
free_uid(user); /* For find_user() */
223229
break;
224230
}
@@ -242,6 +248,8 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
242248
const struct cred *cred = current_cred();
243249
long niceval, retval = -ESRCH;
244250
struct pid *pgrp;
251+
kuid_t cred_uid;
252+
kuid_t uid;
245253

246254
if (which > PRIO_USER || which < PRIO_PROCESS)
247255
return -EINVAL;
@@ -272,21 +280,25 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
272280
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
273281
break;
274282
case PRIO_USER:
283+
cred_uid = make_kuid(cred->user_ns, cred->uid);
284+
uid = make_kuid(cred->user_ns, who);
275285
user = cred->user;
276286
if (!who)
277-
who = cred->uid;
278-
else if ((who != cred->uid) &&
279-
!(user = find_user(who)))
287+
uid = cred_uid;
288+
else if (!uid_eq(uid, cred_uid) &&
289+
!(user = find_user(uid)))
280290
goto out_unlock; /* No processes for this user */
281291

282292
do_each_thread(g, p) {
283-
if (__task_cred(p)->uid == who) {
293+
const struct cred *tcred = __task_cred(p);
294+
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
295+
if (uid_eq(tcred_uid, uid)) {
284296
niceval = 20 - task_nice(p);
285297
if (niceval > retval)
286298
retval = niceval;
287299
}
288300
} while_each_thread(g, p);
289-
if (who != cred->uid)
301+
if (!uid_eq(uid, cred_uid))
290302
free_uid(user); /* for find_user() */
291303
break;
292304
}
@@ -629,7 +641,7 @@ static int set_user(struct cred *new)
629641
{
630642
struct user_struct *new_user;
631643

632-
new_user = alloc_uid(current_user_ns(), new->uid);
644+
new_user = alloc_uid(make_kuid(new->user_ns, new->uid));
633645
if (!new_user)
634646
return -EAGAIN;
635647

kernel/user.c

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@ EXPORT_SYMBOL_GPL(init_user_ns);
3434
* when changing user ID's (ie setuid() and friends).
3535
*/
3636

37+
#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7)
38+
#define UIDHASH_SZ (1 << UIDHASH_BITS)
3739
#define UIDHASH_MASK (UIDHASH_SZ - 1)
3840
#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
39-
#define uidhashentry(ns, uid) ((ns)->uidhash_table + __uidhashfn((uid)))
41+
#define uidhashentry(uid) (uidhash_table + __uidhashfn((__kuid_val(uid))))
4042

4143
static struct kmem_cache *uid_cachep;
44+
struct hlist_head uidhash_table[UIDHASH_SZ];
4245

4346
/*
4447
* The uidhash_lock is mostly taken from process context, but it is
@@ -58,7 +61,7 @@ struct user_struct root_user = {
5861
.files = ATOMIC_INIT(0),
5962
.sigpending = ATOMIC_INIT(0),
6063
.locked_shm = 0,
61-
._user_ns = &init_user_ns,
64+
.uid = GLOBAL_ROOT_UID,
6265
};
6366

6467
/*
@@ -72,16 +75,15 @@ static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
7275
static void uid_hash_remove(struct user_struct *up)
7376
{
7477
hlist_del_init(&up->uidhash_node);
75-
put_user_ns(up->_user_ns); /* It is safe to free the uid hash table now */
7678
}
7779

78-
static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
80+
static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
7981
{
8082
struct user_struct *user;
8183
struct hlist_node *h;
8284

8385
hlist_for_each_entry(user, h, hashent, uidhash_node) {
84-
if (user->uid == uid) {
86+
if (uid_eq(user->uid, uid)) {
8587
atomic_inc(&user->__count);
8688
return user;
8789
}
@@ -110,14 +112,13 @@ static void free_user(struct user_struct *up, unsigned long flags)
110112
*
111113
* If the user_struct could not be found, return NULL.
112114
*/
113-
struct user_struct *find_user(uid_t uid)
115+
struct user_struct *find_user(kuid_t uid)
114116
{
115117
struct user_struct *ret;
116118
unsigned long flags;
117-
struct user_namespace *ns = current_user_ns();
118119

119120
spin_lock_irqsave(&uidhash_lock, flags);
120-
ret = uid_hash_find(uid, uidhashentry(ns, uid));
121+
ret = uid_hash_find(uid, uidhashentry(uid));
121122
spin_unlock_irqrestore(&uidhash_lock, flags);
122123
return ret;
123124
}
@@ -136,9 +137,9 @@ void free_uid(struct user_struct *up)
136137
local_irq_restore(flags);
137138
}
138139

139-
struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
140+
struct user_struct *alloc_uid(kuid_t uid)
140141
{
141-
struct hlist_head *hashent = uidhashentry(ns, uid);
142+
struct hlist_head *hashent = uidhashentry(uid);
142143
struct user_struct *up, *new;
143144

144145
spin_lock_irq(&uidhash_lock);
@@ -153,16 +154,13 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
153154
new->uid = uid;
154155
atomic_set(&new->__count, 1);
155156

156-
new->_user_ns = get_user_ns(ns);
157-
158157
/*
159158
* Before adding this, check whether we raced
160159
* on adding the same user already..
161160
*/
162161
spin_lock_irq(&uidhash_lock);
163162
up = uid_hash_find(uid, hashent);
164163
if (up) {
165-
put_user_ns(ns);
166164
key_put(new->uid_keyring);
167165
key_put(new->session_keyring);
168166
kmem_cache_free(uid_cachep, new);
@@ -187,11 +185,11 @@ static int __init uid_cache_init(void)
187185
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
188186

189187
for(n = 0; n < UIDHASH_SZ; ++n)
190-
INIT_HLIST_HEAD(init_user_ns.uidhash_table + n);
188+
INIT_HLIST_HEAD(uidhash_table + n);
191189

192190
/* Insert the root user immediately (init already runs as root) */
193191
spin_lock_irq(&uidhash_lock);
194-
uid_hash_insert(&root_user, uidhashentry(&init_user_ns, 0));
192+
uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
195193
spin_unlock_irq(&uidhash_lock);
196194

197195
return 0;

kernel/user_namespace.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,15 @@ int create_user_ns(struct cred *new)
2727
{
2828
struct user_namespace *ns, *parent_ns = new->user_ns;
2929
struct user_struct *root_user;
30-
int n;
3130

3231
ns = kmem_cache_alloc(user_ns_cachep, GFP_KERNEL);
3332
if (!ns)
3433
return -ENOMEM;
3534

3635
kref_init(&ns->kref);
3736

38-
for (n = 0; n < UIDHASH_SZ; ++n)
39-
INIT_HLIST_HEAD(ns->uidhash_table + n);
40-
4137
/* Alloc new root user. */
42-
root_user = alloc_uid(ns, 0);
38+
root_user = alloc_uid(make_kuid(ns, 0));
4339
if (!root_user) {
4440
kmem_cache_free(user_ns_cachep, ns);
4541
return -ENOMEM;

0 commit comments

Comments
 (0)