Skip to content

Commit

Permalink
userns: Store uid and gid values in struct cred with kuid_t and kgid_…
Browse files Browse the repository at this point in the history
…t types

cred.h and a few trivial users of struct cred are changed.  The rest of the users
of struct cred are left for other patches as there are too many changes to make
in one go and leave the change reviewable.  If the user namespace is disabled and
CONFIG_UIDGID_STRICT_TYPE_CHECKS are disabled the code will contiue to compile
and behave correctly.

Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
  • Loading branch information
ebiederm committed May 3, 2012
1 parent ae2975b commit 078de5f
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 62 deletions.
2 changes: 1 addition & 1 deletion arch/x86/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
pte_t *pte = lookup_address(address, &level);

if (pte && pte_present(*pte) && !pte_exec(*pte))
printk(nx_warning, current_uid());
printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
}

printk(KERN_ALERT "BUG: unable to handle kernel ");
Expand Down
8 changes: 2 additions & 6 deletions fs/ioprio.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
break;

do_each_thread(g, p) {
const struct cred *tcred = __task_cred(p);
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
if (!uid_eq(tcred_uid, uid))
if (!uid_eq(task_uid(p), uid))
continue;
ret = set_task_ioprio(p, ioprio);
if (ret)
Expand Down Expand Up @@ -220,9 +218,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
break;

do_each_thread(g, p) {
const struct cred *tcred = __task_cred(p);
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
if (!uid_eq(tcred_uid, user->uid))
if (!uid_eq(task_uid(p), user->uid))
continue;
tmpio = get_task_ioprio(p);
if (tmpio < 0)
Expand Down
16 changes: 8 additions & 8 deletions include/linux/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,14 @@ struct cred {
#define CRED_MAGIC 0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
uid_t uid; /* real UID of the task */
gid_t gid; /* real GID of the task */
uid_t suid; /* saved UID of the task */
gid_t sgid; /* saved GID of the task */
uid_t euid; /* effective UID of the task */
gid_t egid; /* effective GID of the task */
uid_t fsuid; /* UID for VFS ops */
gid_t fsgid; /* GID for VFS ops */
kuid_t uid; /* real UID of the task */
kgid_t gid; /* real GID of the task */
kuid_t suid; /* saved UID of the task */
kgid_t sgid; /* saved GID of the task */
kuid_t euid; /* effective UID of the task */
kgid_t egid; /* effective GID of the task */
kuid_t fsuid; /* UID for VFS ops */
kgid_t fsgid; /* GID for VFS ops */
unsigned securebits; /* SUID-less security management */
kernel_cap_t cap_inheritable; /* caps our children can inherit */
kernel_cap_t cap_permitted; /* caps we're permitted */
Expand Down
8 changes: 4 additions & 4 deletions include/linux/user_namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ static inline void put_user_ns(struct user_namespace *ns)
#endif

static inline uid_t user_ns_map_uid(struct user_namespace *to,
const struct cred *cred, uid_t uid)
const struct cred *cred, kuid_t uid)
{
return from_kuid_munged(to, make_kuid(cred->user_ns, uid));
return from_kuid_munged(to, uid);
}

static inline gid_t user_ns_map_gid(struct user_namespace *to,
const struct cred *cred, gid_t gid)
const struct cred *cred, kgid_t gid)
{
return from_kgid_munged(to, make_kgid(cred->user_ns, gid));
return from_kgid_munged(to, gid);
}

#endif /* _LINUX_USER_H */
36 changes: 22 additions & 14 deletions kernel/cred.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ struct cred init_cred = {
.subscribers = ATOMIC_INIT(2),
.magic = CRED_MAGIC,
#endif
.uid = GLOBAL_ROOT_UID,
.gid = GLOBAL_ROOT_GID,
.suid = GLOBAL_ROOT_UID,
.sgid = GLOBAL_ROOT_GID,
.euid = GLOBAL_ROOT_UID,
.egid = GLOBAL_ROOT_GID,
.fsuid = GLOBAL_ROOT_UID,
.fsgid = GLOBAL_ROOT_GID,
.securebits = SECUREBITS_DEFAULT,
.cap_inheritable = CAP_EMPTY_SET,
.cap_permitted = CAP_FULL_SET,
Expand Down Expand Up @@ -488,10 +496,10 @@ int commit_creds(struct cred *new)
get_cred(new); /* we will require a ref for the subj creds too */

/* dumpability changes */
if (old->euid != new->euid ||
old->egid != new->egid ||
old->fsuid != new->fsuid ||
old->fsgid != new->fsgid ||
if (!uid_eq(old->euid, new->euid) ||
!gid_eq(old->egid, new->egid) ||
!uid_eq(old->fsuid, new->fsuid) ||
!gid_eq(old->fsgid, new->fsgid) ||
!cap_issubset(new->cap_permitted, old->cap_permitted)) {
if (task->mm)
set_dumpable(task->mm, suid_dumpable);
Expand All @@ -500,9 +508,9 @@ int commit_creds(struct cred *new)
}

/* alter the thread keyring */
if (new->fsuid != old->fsuid)
if (!uid_eq(new->fsuid, old->fsuid))
key_fsuid_changed(task);
if (new->fsgid != old->fsgid)
if (!gid_eq(new->fsgid, old->fsgid))
key_fsgid_changed(task);

/* do it
Expand All @@ -519,16 +527,16 @@ int commit_creds(struct cred *new)
alter_cred_subscribers(old, -2);

/* send notifications */
if (new->uid != old->uid ||
new->euid != old->euid ||
new->suid != old->suid ||
new->fsuid != old->fsuid)
if (!uid_eq(new->uid, old->uid) ||
!uid_eq(new->euid, old->euid) ||
!uid_eq(new->suid, old->suid) ||
!uid_eq(new->fsuid, old->fsuid))
proc_id_connector(task, PROC_EVENT_UID);

if (new->gid != old->gid ||
new->egid != old->egid ||
new->sgid != old->sgid ||
new->fsgid != old->fsgid)
if (!gid_eq(new->gid, old->gid) ||
!gid_eq(new->egid, old->egid) ||
!gid_eq(new->sgid, old->sgid) ||
!gid_eq(new->fsgid, old->fsgid))
proc_id_connector(task, PROC_EVENT_GID);

/* release the old obj and subj refs both */
Expand Down
14 changes: 8 additions & 6 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,8 +1038,10 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str
if (SI_FROMKERNEL(info))
return;

info->si_uid = user_ns_map_uid(task_cred_xxx(t, user_ns),
current_cred(), info->si_uid);
rcu_read_lock();
info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns),
make_kuid(current_user_ns(), info->si_uid));
rcu_read_unlock();
}
#else
static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
Expand Down Expand Up @@ -1106,7 +1108,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
q->info.si_code = SI_USER;
q->info.si_pid = task_tgid_nr_ns(current,
task_active_pid_ns(t));
q->info.si_uid = current_uid();
q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
break;
case (unsigned long) SEND_SIG_PRIV:
q->info.si_signo = sig;
Expand Down Expand Up @@ -1973,7 +1975,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
info.si_signo = signr;
info.si_code = exit_code;
info.si_pid = task_pid_vnr(current);
info.si_uid = current_uid();
info.si_uid = from_kuid_munged(current_user_ns(), current_uid());

/* Let the debugger run. */
ptrace_stop(exit_code, why, 1, &info);
Expand Down Expand Up @@ -2828,7 +2830,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
info.si_errno = 0;
info.si_code = SI_USER;
info.si_pid = task_tgid_vnr(current);
info.si_uid = current_uid();
info.si_uid = from_kuid_munged(current_user_ns(), current_uid());

return kill_something_info(sig, &info, pid);
}
Expand Down Expand Up @@ -2871,7 +2873,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
info.si_errno = 0;
info.si_code = SI_TKILL;
info.si_pid = task_tgid_vnr(current);
info.si_uid = current_uid();
info.si_uid = from_kuid_munged(current_user_ns(), current_uid());

return do_send_specific(tgid, pid, sig, &info);
}
Expand Down
26 changes: 9 additions & 17 deletions kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
const struct cred *cred = current_cred();
int error = -EINVAL;
struct pid *pgrp;
kuid_t cred_uid;
kuid_t uid;

if (which > PRIO_USER || which < PRIO_PROCESS)
Expand Down Expand Up @@ -209,22 +208,19 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
cred_uid = make_kuid(cred->user_ns, cred->uid);
uid = make_kuid(cred->user_ns, who);
user = cred->user;
if (!who)
uid = cred_uid;
else if (!uid_eq(uid, cred_uid) &&
uid = cred->uid;
else if (!uid_eq(uid, cred->uid) &&
!(user = find_user(uid)))
goto out_unlock; /* No processes for this user */

do_each_thread(g, p) {
const struct cred *tcred = __task_cred(p);
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
if (uid_eq(tcred_uid, uid))
if (uid_eq(task_uid(p), uid))
error = set_one_prio(p, niceval, error);
} while_each_thread(g, p);
if (!uid_eq(uid, cred_uid))
if (!uid_eq(uid, cred->uid))
free_uid(user); /* For find_user() */
break;
}
Expand All @@ -248,7 +244,6 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
const struct cred *cred = current_cred();
long niceval, retval = -ESRCH;
struct pid *pgrp;
kuid_t cred_uid;
kuid_t uid;

if (which > PRIO_USER || which < PRIO_PROCESS)
Expand Down Expand Up @@ -280,25 +275,22 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
cred_uid = make_kuid(cred->user_ns, cred->uid);
uid = make_kuid(cred->user_ns, who);
user = cred->user;
if (!who)
uid = cred_uid;
else if (!uid_eq(uid, cred_uid) &&
uid = cred->uid;
else if (!uid_eq(uid, cred->uid) &&
!(user = find_user(uid)))
goto out_unlock; /* No processes for this user */

do_each_thread(g, p) {
const struct cred *tcred = __task_cred(p);
kuid_t tcred_uid = make_kuid(tcred->user_ns, tcred->uid);
if (uid_eq(tcred_uid, uid)) {
if (uid_eq(task_uid(p), uid)) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
}
} while_each_thread(g, p);
if (!uid_eq(uid, cred_uid))
if (!uid_eq(uid, cred->uid))
free_uid(user); /* for find_user() */
break;
}
Expand Down Expand Up @@ -641,7 +633,7 @@ static int set_user(struct cred *new)
{
struct user_struct *new_user;

new_user = alloc_uid(make_kuid(new->user_ns, new->uid));
new_user = alloc_uid(new->uid);
if (!new_user)
return -EAGAIN;

Expand Down
4 changes: 2 additions & 2 deletions kernel/user_namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
int create_user_ns(struct cred *new)
{
struct user_namespace *ns, *parent_ns = new->user_ns;
kuid_t owner = make_kuid(new->user_ns, new->euid);
kgid_t group = make_kgid(new->user_ns, new->egid);
kuid_t owner = new->euid;
kgid_t group = new->egid;

/* The creator needs a mapping in the parent user namespace
* or else we won't be able to reasonably tell userspace who
Expand Down
4 changes: 2 additions & 2 deletions mm/oom_kill.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,8 @@ static void dump_tasks(const struct mem_cgroup *memcg, const nodemask_t *nodemas
}

pr_info("[%5d] %5d %5d %8lu %8lu %3u %3d %5d %s\n",
task->pid, task_uid(task), task->tgid,
task->mm->total_vm, get_mm_rss(task->mm),
task->pid, from_kuid(&init_user_ns, task_uid(task)),
task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
task_cpu(task), task->signal->oom_adj,
task->signal->oom_score_adj, task->comm);
task_unlock(task);
Expand Down
3 changes: 1 addition & 2 deletions security/commoncap.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
{
for (;;) {
/* The owner of the user namespace has all caps. */
if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner,
make_kuid(cred->user_ns, cred->euid)))
if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid))
return 0;

/* Do we have the necessary capabilities? */
Expand Down

0 comments on commit 078de5f

Please sign in to comment.