Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

userns: Convert net/core/scm.c to use kuids and kgids

With the existence of kuid_t and kgid_t we can take this further
and remove the usage of struct cred altogether, ensuring we
don't get cache line misses from reference counts. For now
however start simply and do a straight forward conversion
I can be certain is correct.

In cred_to_ucred use from_kuid_munged and from_kgid_munged
as these values are going directly to userspace and we want to use
the userspace safe values not -1 when reporting a value that does not
map. The earlier conversion that used from_kuid was buggy in that
respect. Oops.

Cc: Eric Dumazet <eric.dumazet@gmail.com>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

+25 -10
+23 -8
net/core/scm.c
··· 45 45 static __inline__ int scm_check_creds(struct ucred *creds) 46 46 { 47 47 const struct cred *cred = current_cred(); 48 + kuid_t uid = make_kuid(cred->user_ns, creds->uid); 49 + kgid_t gid = make_kgid(cred->user_ns, creds->gid); 50 + 51 + if (!uid_valid(uid) || !gid_valid(gid)) 52 + return -EINVAL; 48 53 49 54 if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) && 50 - ((creds->uid == cred->uid || creds->uid == cred->euid || 51 - creds->uid == cred->suid) || capable(CAP_SETUID)) && 52 - ((creds->gid == cred->gid || creds->gid == cred->egid || 53 - creds->gid == cred->sgid) || capable(CAP_SETGID))) { 55 + ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) || 56 + uid_eq(uid, cred->suid)) || capable(CAP_SETUID)) && 57 + ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) || 58 + gid_eq(gid, cred->sgid)) || capable(CAP_SETGID))) { 54 59 return 0; 55 60 } 56 61 return -EPERM; ··· 154 149 goto error; 155 150 break; 156 151 case SCM_CREDENTIALS: 152 + { 153 + kuid_t uid; 154 + kgid_t gid; 157 155 if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) 158 156 goto error; 159 157 memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred)); ··· 174 166 p->pid = pid; 175 167 } 176 168 169 + err = -EINVAL; 170 + uid = make_kuid(current_user_ns(), p->creds.uid); 171 + gid = make_kgid(current_user_ns(), p->creds.gid); 172 + if (!uid_valid(uid) || !gid_valid(gid)) 173 + goto error; 174 + 177 175 if (!p->cred || 178 - (p->cred->euid != p->creds.uid) || 179 - (p->cred->egid != p->creds.gid)) { 176 + !uid_eq(p->cred->euid, uid) || 177 + !gid_eq(p->cred->egid, gid)) { 180 178 struct cred *cred; 181 179 err = -ENOMEM; 182 180 cred = prepare_creds(); 183 181 if (!cred) 184 182 goto error; 185 183 186 - cred->uid = cred->euid = p->creds.uid; 187 - cred->gid = cred->egid = p->creds.gid; 184 + cred->uid = cred->euid = uid; 185 + cred->gid = cred->egid = gid; 188 186 if (p->cred) 189 187 put_cred(p->cred); 190 188 p->cred = cred; 191 189 } 192 190 break; 191 + } 193 192 default: 194 193 goto error; 195 194 }
+2 -2
net/core/sock.c
··· 868 868 if (cred) { 869 869 struct user_namespace *current_ns = current_user_ns(); 870 870 871 - ucred->uid = from_kuid(current_ns, cred->euid); 872 - ucred->gid = from_kgid(current_ns, cred->egid); 871 + ucred->uid = from_kuid_munged(current_ns, cred->euid); 872 + ucred->gid = from_kgid_munged(current_ns, cred->egid); 873 873 } 874 874 } 875 875 EXPORT_SYMBOL_GPL(cred_to_ucred);