userns: Don't let unprivileged users trick privileged users into setting the id_map
When we require privilege for setting /proc/<pid>/uid_map or /proc/<pid>/gid_map no longer allow an unprivileged user to open the file and pass it to a privileged program to write to the file. Instead when privilege is required require both the opener and the writer to have the necessary capabilities. I have tested this code and verified that setting /proc/<pid>/uid_map fails when an unprivileged user opens the file and a privielged user attempts to set the mapping, that unprivileged users can still map their own id, and that a privileged users can still setup an arbitrary mapping. Reported-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andy Lutomirski <luto@amacapital.net>
This commit is contained in:
committed by
Andy Lutomirski
parent
6c4c4d4bda
commit
6708075f10
@@ -25,7 +25,8 @@
|
|||||||
|
|
||||||
static struct kmem_cache *user_ns_cachep __read_mostly;
|
static struct kmem_cache *user_ns_cachep __read_mostly;
|
||||||
|
|
||||||
static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
|
static bool new_idmap_permitted(const struct file *file,
|
||||||
|
struct user_namespace *ns, int cap_setid,
|
||||||
struct uid_gid_map *map);
|
struct uid_gid_map *map);
|
||||||
|
|
||||||
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
|
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
|
||||||
@@ -700,7 +701,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
|
|||||||
|
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
/* Validate the user is allowed to use user id's mapped to. */
|
/* Validate the user is allowed to use user id's mapped to. */
|
||||||
if (!new_idmap_permitted(ns, cap_setid, &new_map))
|
if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Map the lower ids from the parent user namespace to the
|
/* Map the lower ids from the parent user namespace to the
|
||||||
@@ -787,7 +788,8 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t
|
|||||||
&ns->projid_map, &ns->parent->projid_map);
|
&ns->projid_map, &ns->parent->projid_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
|
static bool new_idmap_permitted(const struct file *file,
|
||||||
|
struct user_namespace *ns, int cap_setid,
|
||||||
struct uid_gid_map *new_map)
|
struct uid_gid_map *new_map)
|
||||||
{
|
{
|
||||||
/* Allow mapping to your own filesystem ids */
|
/* Allow mapping to your own filesystem ids */
|
||||||
@@ -811,8 +813,10 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
|
|||||||
|
|
||||||
/* Allow the specified ids if we have the appropriate capability
|
/* Allow the specified ids if we have the appropriate capability
|
||||||
* (CAP_SETUID or CAP_SETGID) over the parent user namespace.
|
* (CAP_SETUID or CAP_SETGID) over the parent user namespace.
|
||||||
|
* And the opener of the id file also had the approprpiate capability.
|
||||||
*/
|
*/
|
||||||
if (ns_capable(ns->parent, cap_setid))
|
if (ns_capable(ns->parent, cap_setid) &&
|
||||||
|
file_ns_capable(file, ns->parent, cap_setid))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
Reference in New Issue
Block a user