Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-17 Thread Andy Lutomirski
On Fri, Dec 14, 2012 at 4:48 PM, Eric W. Biederman
 wrote:
>
> When unsharing a user namespace we reduce our credentials to just what
> can be done in that user namespace.  This is a subset of the credentials
> we previously had.  Teach commit_creds to recognize this is a subset
> of the credentials we have had before and don't clear the dumpability flag.
>
> This allows an unprivileged  program to do:
> unshare(CLONE_NEWUSER);
> fd = open("/proc/self/uid_map", O_RDWR);
>
> Where previously opening the uid_map writable would fail because
> the the task had been made non-dumpable.
>
> Signed-off-by: "Eric W. Biederman" 
> ---
>  kernel/cred.c |   27 ++-
>  1 files changed, 26 insertions(+), 1 deletions(-)
>
> diff --git a/kernel/cred.c b/kernel/cred.c
> index 48cea3d..709d521 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -455,6 +455,31 @@ error_put:
> return ret;
>  }
>
> +static bool cred_cap_issubset(const struct cred *set, const struct cred 
> *subset)
> +{
> +   const struct user_namespace *set_ns = set->user_ns;
> +   const struct user_namespace *subset_ns = subset->user_ns;
> +
> +   /* If the two credentials are in the same user namespace see if
> +* the capabilities of subset are a subset of set.
> +*/
> +   if (set_ns == subset_ns)
> +   return cap_issubset(subset->cap_permitted, 
> set->cap_permitted);
> +
> +   /* The credentials are in a different user namespaces
> +* therefore one is a subset of the other only if a set is an
> +* ancestor of subset and set->euid is owner of subset or one
> +* of subsets ancestors.
> +*/
> +   for (;subset_ns != _user_ns; subset_ns = subset_ns->parent) {
> +   if ((set_ns == subset_ns->parent)  &&
> +   uid_eq(subset_ns->owner, set->euid))
> +   return true;
> +   }
> +
> +   return false;
> +}
> +
>  /**
>   * commit_creds - Install new credentials upon the current task
>   * @new: The credentials to be assigned
> @@ -493,7 +518,7 @@ int commit_creds(struct cred *new)
> !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)) {
> +   !cred_cap_issubset(old, new)) {
> if (task->mm)
> set_dumpable(task->mm, suid_dumpable);
> task->pdeath_signal = 0;
> --
> 1.7.5.4
>

Acked-by: Andy Lutomirski 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-17 Thread Andy Lutomirski
On Fri, Dec 14, 2012 at 4:48 PM, Eric W. Biederman
ebied...@xmission.com wrote:

 When unsharing a user namespace we reduce our credentials to just what
 can be done in that user namespace.  This is a subset of the credentials
 we previously had.  Teach commit_creds to recognize this is a subset
 of the credentials we have had before and don't clear the dumpability flag.

 This allows an unprivileged  program to do:
 unshare(CLONE_NEWUSER);
 fd = open(/proc/self/uid_map, O_RDWR);

 Where previously opening the uid_map writable would fail because
 the the task had been made non-dumpable.

 Signed-off-by: Eric W. Biederman ebied...@xmission.com
 ---
  kernel/cred.c |   27 ++-
  1 files changed, 26 insertions(+), 1 deletions(-)

 diff --git a/kernel/cred.c b/kernel/cred.c
 index 48cea3d..709d521 100644
 --- a/kernel/cred.c
 +++ b/kernel/cred.c
 @@ -455,6 +455,31 @@ error_put:
 return ret;
  }

 +static bool cred_cap_issubset(const struct cred *set, const struct cred 
 *subset)
 +{
 +   const struct user_namespace *set_ns = set-user_ns;
 +   const struct user_namespace *subset_ns = subset-user_ns;
 +
 +   /* If the two credentials are in the same user namespace see if
 +* the capabilities of subset are a subset of set.
 +*/
 +   if (set_ns == subset_ns)
 +   return cap_issubset(subset-cap_permitted, 
 set-cap_permitted);
 +
 +   /* The credentials are in a different user namespaces
 +* therefore one is a subset of the other only if a set is an
 +* ancestor of subset and set-euid is owner of subset or one
 +* of subsets ancestors.
 +*/
 +   for (;subset_ns != init_user_ns; subset_ns = subset_ns-parent) {
 +   if ((set_ns == subset_ns-parent)  
 +   uid_eq(subset_ns-owner, set-euid))
 +   return true;
 +   }
 +
 +   return false;
 +}
 +
  /**
   * commit_creds - Install new credentials upon the current task
   * @new: The credentials to be assigned
 @@ -493,7 +518,7 @@ int commit_creds(struct cred *new)
 !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)) {
 +   !cred_cap_issubset(old, new)) {
 if (task-mm)
 set_dumpable(task-mm, suid_dumpable);
 task-pdeath_signal = 0;
 --
 1.7.5.4


Acked-by: Andy Lutomirski l...@amacapital.net
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Serge E. Hallyn
Quoting Eric W. Biederman (ebied...@xmission.com):
> 
> When unsharing a user namespace we reduce our credentials to just what
> can be done in that user namespace.  This is a subset of the credentials
> we previously had.  Teach commit_creds to recognize this is a subset
> of the credentials we have had before and don't clear the dumpability flag.
> 
> This allows an unprivileged  program to do:
> unshare(CLONE_NEWUSER);
> fd = open("/proc/self/uid_map", O_RDWR);
> 
> Where previously opening the uid_map writable would fail because
> the the task had been made non-dumpable.
> 
> Signed-off-by: "Eric W. Biederman" 

Acked-by: Serge Hallyn 

> ---
>  kernel/cred.c |   27 ++-
>  1 files changed, 26 insertions(+), 1 deletions(-)
> 
> diff --git a/kernel/cred.c b/kernel/cred.c
> index 48cea3d..709d521 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -455,6 +455,31 @@ error_put:
>   return ret;
>  }
>  
> +static bool cred_cap_issubset(const struct cred *set, const struct cred 
> *subset)
> +{
> + const struct user_namespace *set_ns = set->user_ns;
> + const struct user_namespace *subset_ns = subset->user_ns;
> +
> + /* If the two credentials are in the same user namespace see if
> +  * the capabilities of subset are a subset of set.
> +  */
> + if (set_ns == subset_ns)
> + return cap_issubset(subset->cap_permitted, set->cap_permitted);
> +
> + /* The credentials are in a different user namespaces
> +  * therefore one is a subset of the other only if a set is an
> +  * ancestor of subset and set->euid is owner of subset or one
> +  * of subsets ancestors.
> +  */
> + for (;subset_ns != _user_ns; subset_ns = subset_ns->parent) {
> + if ((set_ns == subset_ns->parent)  &&
> + uid_eq(subset_ns->owner, set->euid))
> + return true;
> + }
> +
> + return false;
> +}
> +
>  /**
>   * commit_creds - Install new credentials upon the current task
>   * @new: The credentials to be assigned
> @@ -493,7 +518,7 @@ int commit_creds(struct cred *new)
>   !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)) {
> + !cred_cap_issubset(old, new)) {
>   if (task->mm)
>   set_dumpable(task->mm, suid_dumpable);
>   task->pdeath_signal = 0;
> -- 
> 1.7.5.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Eric W. Biederman

When unsharing a user namespace we reduce our credentials to just what
can be done in that user namespace.  This is a subset of the credentials
we previously had.  Teach commit_creds to recognize this is a subset
of the credentials we have had before and don't clear the dumpability flag.

This allows an unprivileged  program to do:
unshare(CLONE_NEWUSER);
fd = open("/proc/self/uid_map", O_RDWR);

Where previously opening the uid_map writable would fail because
the the task had been made non-dumpable.

Signed-off-by: "Eric W. Biederman" 
---
 kernel/cred.c |   27 ++-
 1 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/kernel/cred.c b/kernel/cred.c
index 48cea3d..709d521 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -455,6 +455,31 @@ error_put:
return ret;
 }
 
+static bool cred_cap_issubset(const struct cred *set, const struct cred 
*subset)
+{
+   const struct user_namespace *set_ns = set->user_ns;
+   const struct user_namespace *subset_ns = subset->user_ns;
+
+   /* If the two credentials are in the same user namespace see if
+* the capabilities of subset are a subset of set.
+*/
+   if (set_ns == subset_ns)
+   return cap_issubset(subset->cap_permitted, set->cap_permitted);
+
+   /* The credentials are in a different user namespaces
+* therefore one is a subset of the other only if a set is an
+* ancestor of subset and set->euid is owner of subset or one
+* of subsets ancestors.
+*/
+   for (;subset_ns != _user_ns; subset_ns = subset_ns->parent) {
+   if ((set_ns == subset_ns->parent)  &&
+   uid_eq(subset_ns->owner, set->euid))
+   return true;
+   }
+
+   return false;
+}
+
 /**
  * commit_creds - Install new credentials upon the current task
  * @new: The credentials to be assigned
@@ -493,7 +518,7 @@ int commit_creds(struct cred *new)
!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)) {
+   !cred_cap_issubset(old, new)) {
if (task->mm)
set_dumpable(task->mm, suid_dumpable);
task->pdeath_signal = 0;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Serge E. Hallyn
Quoting Eric W. Biederman (ebied...@xmission.com):
> "Serge E. Hallyn"  writes:
> 
> > Quoting Eric W. Biederman (ebied...@xmission.com):
> >> 
> >> When unsharing a user namespace we reduce our credentials to just what
> >> can be done in that user namespace.  This is a subset of the credentials
> >> we previously had.  Teach commit_creds to recognize this is a subset
> >> of the credentials we have had before and don't clear the dumpability flag.
> >> 
> >> This allows an unprivileged  program to do:
> >> unshare(CLONE_NEWUSER);
> >> fd = open("/proc/self/uid_map", O_RDWR);
> >> 
> >> Where previously opening the uid_map writable would fail because
> >> the the task had been made non-dumpable.
> >> 
> >> Signed-off-by: "Eric W. Biederman" 
> >
> > Acked-by: Serge Hallyn 
> >
> >> ---
> >>  kernel/cred.c |   26 +-
> >>  1 files changed, 25 insertions(+), 1 deletions(-)
> >> 
> >> diff --git a/kernel/cred.c b/kernel/cred.c
> >> index 48cea3d..993a7ea41 100644
> >> --- a/kernel/cred.c
> >> +++ b/kernel/cred.c
> >> @@ -455,6 +455,30 @@ error_put:
> >>return ret;
> >>  }
> >>  
> >
> > Do you think we need to warn that this can only be used for
> > commit_creds?  (i.e. if someone tried ot use this in some
> > other context, the 'creds are subset of target ns is a child
> > of current_ns' assumption would be wrong)
> 
> This function should be a general test valid at any time.
> 
> Except that I forgot the bit of the test that asks is the original cred
> the owner of the subset user namespace.

Ok, with that change that'll be fine :)

> I will respin this patch.

Cool, thanks.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Eric W. Biederman
"Serge E. Hallyn"  writes:

> Quoting Eric W. Biederman (ebied...@xmission.com):
>> 
>> When unsharing a user namespace we reduce our credentials to just what
>> can be done in that user namespace.  This is a subset of the credentials
>> we previously had.  Teach commit_creds to recognize this is a subset
>> of the credentials we have had before and don't clear the dumpability flag.
>> 
>> This allows an unprivileged  program to do:
>> unshare(CLONE_NEWUSER);
>> fd = open("/proc/self/uid_map", O_RDWR);
>> 
>> Where previously opening the uid_map writable would fail because
>> the the task had been made non-dumpable.
>> 
>> Signed-off-by: "Eric W. Biederman" 
>
> Acked-by: Serge Hallyn 
>
>> ---
>>  kernel/cred.c |   26 +-
>>  1 files changed, 25 insertions(+), 1 deletions(-)
>> 
>> diff --git a/kernel/cred.c b/kernel/cred.c
>> index 48cea3d..993a7ea41 100644
>> --- a/kernel/cred.c
>> +++ b/kernel/cred.c
>> @@ -455,6 +455,30 @@ error_put:
>>  return ret;
>>  }
>>  
>
> Do you think we need to warn that this can only be used for
> commit_creds?  (i.e. if someone tried ot use this in some
> other context, the 'creds are subset of target ns is a child
> of current_ns' assumption would be wrong)

This function should be a general test valid at any time.

Except that I forgot the bit of the test that asks is the original cred
the owner of the subset user namespace.

I will respin this patch.

As a small segway this property that unshare(CLONE_NEWUSER) results
in a subset of the capabilities a process already had is a very
important property to make it possible to reason about user namespaces.
Maintaining this property is the reason behind the choices I made
in fixing cap_capable.

>> +static bool cred_cap_issubset(const struct cred *set, const struct cred 
>> *subset)
>> +{
>> +const struct user_namespace *set_ns = set->user_ns;
>> +const struct user_namespace *subset_ns = subset->user_ns;
>> +
>> +/* If the two credentials are in the same user namespace see if
>> + * the capabilities of subset are a subset of set.
>> + */
>> +if (set_ns == subset_ns)
>> +return cap_issubset(subset->cap_permitted, set->cap_permitted);
>> +
>> +/* The credentials are in a different user namespaces
>
> This can only happen during setns and CLONE_NEWUSER right?

Right.  This can only happen during setns, unshare(CLONE_NEWUSER),
and possibly during clone.  Otherwise we are not changing the user
namespace.  However for clarity and robustness I don't want the code
to rely on that.

>> + * therefore one is a subset of the other only if a set is an
>> + * ancestor of subset.
>> + */
>
>> +while (subset_ns != _user_ns) {
>> +if (set_ns == subset_ns->parent)
>> +return true;
>> +subset_ns = subset_ns->parent;
>> +}
>> +
>> +return false;
>> +}
>> +
>>  /**
>>   * commit_creds - Install new credentials upon the current task
>>   * @new: The credentials to be assigned
>> @@ -493,7 +517,7 @@ int commit_creds(struct cred *new)
>>  !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)) {
>> +!cred_cap_issubset(old, new)) {
>>  if (task->mm)
>>  set_dumpable(task->mm, suid_dumpable);
>>  task->pdeath_signal = 0;
>> -- 
>> 1.7.5.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Serge E. Hallyn
Quoting Eric W. Biederman (ebied...@xmission.com):
> 
> When unsharing a user namespace we reduce our credentials to just what
> can be done in that user namespace.  This is a subset of the credentials
> we previously had.  Teach commit_creds to recognize this is a subset
> of the credentials we have had before and don't clear the dumpability flag.
> 
> This allows an unprivileged  program to do:
> unshare(CLONE_NEWUSER);
> fd = open("/proc/self/uid_map", O_RDWR);
> 
> Where previously opening the uid_map writable would fail because
> the the task had been made non-dumpable.
> 
> Signed-off-by: "Eric W. Biederman" 

Acked-by: Serge Hallyn 

> ---
>  kernel/cred.c |   26 +-
>  1 files changed, 25 insertions(+), 1 deletions(-)
> 
> diff --git a/kernel/cred.c b/kernel/cred.c
> index 48cea3d..993a7ea41 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -455,6 +455,30 @@ error_put:
>   return ret;
>  }
>  

Do you think we need to warn that this can only be used for
commit_creds?  (i.e. if someone tried ot use this in some
other context, the 'creds are subset of target ns is a child
of current_ns' assumption would be wrong)

> +static bool cred_cap_issubset(const struct cred *set, const struct cred 
> *subset)
> +{
> + const struct user_namespace *set_ns = set->user_ns;
> + const struct user_namespace *subset_ns = subset->user_ns;
> +
> + /* If the two credentials are in the same user namespace see if
> +  * the capabilities of subset are a subset of set.
> +  */
> + if (set_ns == subset_ns)
> + return cap_issubset(subset->cap_permitted, set->cap_permitted);
> +
> + /* The credentials are in a different user namespaces

This can only happen during setns and CLONE_NEWUSER right?

> +  * therefore one is a subset of the other only if a set is an
> +  * ancestor of subset.
> +  */

> + while (subset_ns != _user_ns) {
> + if (set_ns == subset_ns->parent)
> + return true;
> + subset_ns = subset_ns->parent;
> + }
> +
> + return false;
> +}
> +
>  /**
>   * commit_creds - Install new credentials upon the current task
>   * @new: The credentials to be assigned
> @@ -493,7 +517,7 @@ int commit_creds(struct cred *new)
>   !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)) {
> + !cred_cap_issubset(old, new)) {
>   if (task->mm)
>   set_dumpable(task->mm, suid_dumpable);
>   task->pdeath_signal = 0;
> -- 
> 1.7.5.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Eric W. Biederman

When unsharing a user namespace we reduce our credentials to just what
can be done in that user namespace.  This is a subset of the credentials
we previously had.  Teach commit_creds to recognize this is a subset
of the credentials we have had before and don't clear the dumpability flag.

This allows an unprivileged  program to do:
unshare(CLONE_NEWUSER);
fd = open("/proc/self/uid_map", O_RDWR);

Where previously opening the uid_map writable would fail because
the the task had been made non-dumpable.

Signed-off-by: "Eric W. Biederman" 
---
 kernel/cred.c |   26 +-
 1 files changed, 25 insertions(+), 1 deletions(-)

diff --git a/kernel/cred.c b/kernel/cred.c
index 48cea3d..993a7ea41 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -455,6 +455,30 @@ error_put:
return ret;
 }
 
+static bool cred_cap_issubset(const struct cred *set, const struct cred 
*subset)
+{
+   const struct user_namespace *set_ns = set->user_ns;
+   const struct user_namespace *subset_ns = subset->user_ns;
+
+   /* If the two credentials are in the same user namespace see if
+* the capabilities of subset are a subset of set.
+*/
+   if (set_ns == subset_ns)
+   return cap_issubset(subset->cap_permitted, set->cap_permitted);
+
+   /* The credentials are in a different user namespaces
+* therefore one is a subset of the other only if a set is an
+* ancestor of subset.
+*/
+   while (subset_ns != _user_ns) {
+   if (set_ns == subset_ns->parent)
+   return true;
+   subset_ns = subset_ns->parent;
+   }
+
+   return false;
+}
+
 /**
  * commit_creds - Install new credentials upon the current task
  * @new: The credentials to be assigned
@@ -493,7 +517,7 @@ int commit_creds(struct cred *new)
!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)) {
+   !cred_cap_issubset(old, new)) {
if (task->mm)
set_dumpable(task->mm, suid_dumpable);
task->pdeath_signal = 0;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Eric W. Biederman

When unsharing a user namespace we reduce our credentials to just what
can be done in that user namespace.  This is a subset of the credentials
we previously had.  Teach commit_creds to recognize this is a subset
of the credentials we have had before and don't clear the dumpability flag.

This allows an unprivileged  program to do:
unshare(CLONE_NEWUSER);
fd = open(/proc/self/uid_map, O_RDWR);

Where previously opening the uid_map writable would fail because
the the task had been made non-dumpable.

Signed-off-by: Eric W. Biederman ebied...@xmission.com
---
 kernel/cred.c |   26 +-
 1 files changed, 25 insertions(+), 1 deletions(-)

diff --git a/kernel/cred.c b/kernel/cred.c
index 48cea3d..993a7ea41 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -455,6 +455,30 @@ error_put:
return ret;
 }
 
+static bool cred_cap_issubset(const struct cred *set, const struct cred 
*subset)
+{
+   const struct user_namespace *set_ns = set-user_ns;
+   const struct user_namespace *subset_ns = subset-user_ns;
+
+   /* If the two credentials are in the same user namespace see if
+* the capabilities of subset are a subset of set.
+*/
+   if (set_ns == subset_ns)
+   return cap_issubset(subset-cap_permitted, set-cap_permitted);
+
+   /* The credentials are in a different user namespaces
+* therefore one is a subset of the other only if a set is an
+* ancestor of subset.
+*/
+   while (subset_ns != init_user_ns) {
+   if (set_ns == subset_ns-parent)
+   return true;
+   subset_ns = subset_ns-parent;
+   }
+
+   return false;
+}
+
 /**
  * commit_creds - Install new credentials upon the current task
  * @new: The credentials to be assigned
@@ -493,7 +517,7 @@ int commit_creds(struct cred *new)
!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)) {
+   !cred_cap_issubset(old, new)) {
if (task-mm)
set_dumpable(task-mm, suid_dumpable);
task-pdeath_signal = 0;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Serge E. Hallyn
Quoting Eric W. Biederman (ebied...@xmission.com):
 
 When unsharing a user namespace we reduce our credentials to just what
 can be done in that user namespace.  This is a subset of the credentials
 we previously had.  Teach commit_creds to recognize this is a subset
 of the credentials we have had before and don't clear the dumpability flag.
 
 This allows an unprivileged  program to do:
 unshare(CLONE_NEWUSER);
 fd = open(/proc/self/uid_map, O_RDWR);
 
 Where previously opening the uid_map writable would fail because
 the the task had been made non-dumpable.
 
 Signed-off-by: Eric W. Biederman ebied...@xmission.com

Acked-by: Serge Hallyn serge.hal...@canonical.com

 ---
  kernel/cred.c |   26 +-
  1 files changed, 25 insertions(+), 1 deletions(-)
 
 diff --git a/kernel/cred.c b/kernel/cred.c
 index 48cea3d..993a7ea41 100644
 --- a/kernel/cred.c
 +++ b/kernel/cred.c
 @@ -455,6 +455,30 @@ error_put:
   return ret;
  }
  

Do you think we need to warn that this can only be used for
commit_creds?  (i.e. if someone tried ot use this in some
other context, the 'creds are subset of target ns is a child
of current_ns' assumption would be wrong)

 +static bool cred_cap_issubset(const struct cred *set, const struct cred 
 *subset)
 +{
 + const struct user_namespace *set_ns = set-user_ns;
 + const struct user_namespace *subset_ns = subset-user_ns;
 +
 + /* If the two credentials are in the same user namespace see if
 +  * the capabilities of subset are a subset of set.
 +  */
 + if (set_ns == subset_ns)
 + return cap_issubset(subset-cap_permitted, set-cap_permitted);
 +
 + /* The credentials are in a different user namespaces

This can only happen during setns and CLONE_NEWUSER right?

 +  * therefore one is a subset of the other only if a set is an
 +  * ancestor of subset.
 +  */

 + while (subset_ns != init_user_ns) {
 + if (set_ns == subset_ns-parent)
 + return true;
 + subset_ns = subset_ns-parent;
 + }
 +
 + return false;
 +}
 +
  /**
   * commit_creds - Install new credentials upon the current task
   * @new: The credentials to be assigned
 @@ -493,7 +517,7 @@ int commit_creds(struct cred *new)
   !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)) {
 + !cred_cap_issubset(old, new)) {
   if (task-mm)
   set_dumpable(task-mm, suid_dumpable);
   task-pdeath_signal = 0;
 -- 
 1.7.5.4
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Eric W. Biederman
Serge E. Hallyn se...@hallyn.com writes:

 Quoting Eric W. Biederman (ebied...@xmission.com):
 
 When unsharing a user namespace we reduce our credentials to just what
 can be done in that user namespace.  This is a subset of the credentials
 we previously had.  Teach commit_creds to recognize this is a subset
 of the credentials we have had before and don't clear the dumpability flag.
 
 This allows an unprivileged  program to do:
 unshare(CLONE_NEWUSER);
 fd = open(/proc/self/uid_map, O_RDWR);
 
 Where previously opening the uid_map writable would fail because
 the the task had been made non-dumpable.
 
 Signed-off-by: Eric W. Biederman ebied...@xmission.com

 Acked-by: Serge Hallyn serge.hal...@canonical.com

 ---
  kernel/cred.c |   26 +-
  1 files changed, 25 insertions(+), 1 deletions(-)
 
 diff --git a/kernel/cred.c b/kernel/cred.c
 index 48cea3d..993a7ea41 100644
 --- a/kernel/cred.c
 +++ b/kernel/cred.c
 @@ -455,6 +455,30 @@ error_put:
  return ret;
  }
  

 Do you think we need to warn that this can only be used for
 commit_creds?  (i.e. if someone tried ot use this in some
 other context, the 'creds are subset of target ns is a child
 of current_ns' assumption would be wrong)

This function should be a general test valid at any time.

Except that I forgot the bit of the test that asks is the original cred
the owner of the subset user namespace.

I will respin this patch.

As a small segway this property that unshare(CLONE_NEWUSER) results
in a subset of the capabilities a process already had is a very
important property to make it possible to reason about user namespaces.
Maintaining this property is the reason behind the choices I made
in fixing cap_capable.

 +static bool cred_cap_issubset(const struct cred *set, const struct cred 
 *subset)
 +{
 +const struct user_namespace *set_ns = set-user_ns;
 +const struct user_namespace *subset_ns = subset-user_ns;
 +
 +/* If the two credentials are in the same user namespace see if
 + * the capabilities of subset are a subset of set.
 + */
 +if (set_ns == subset_ns)
 +return cap_issubset(subset-cap_permitted, set-cap_permitted);
 +
 +/* The credentials are in a different user namespaces

 This can only happen during setns and CLONE_NEWUSER right?

Right.  This can only happen during setns, unshare(CLONE_NEWUSER),
and possibly during clone.  Otherwise we are not changing the user
namespace.  However for clarity and robustness I don't want the code
to rely on that.

 + * therefore one is a subset of the other only if a set is an
 + * ancestor of subset.
 + */

 +while (subset_ns != init_user_ns) {
 +if (set_ns == subset_ns-parent)
 +return true;
 +subset_ns = subset_ns-parent;
 +}
 +
 +return false;
 +}
 +
  /**
   * commit_creds - Install new credentials upon the current task
   * @new: The credentials to be assigned
 @@ -493,7 +517,7 @@ int commit_creds(struct cred *new)
  !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)) {
 +!cred_cap_issubset(old, new)) {
  if (task-mm)
  set_dumpable(task-mm, suid_dumpable);
  task-pdeath_signal = 0;
 -- 
 1.7.5.4
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Serge E. Hallyn
Quoting Eric W. Biederman (ebied...@xmission.com):
 Serge E. Hallyn se...@hallyn.com writes:
 
  Quoting Eric W. Biederman (ebied...@xmission.com):
  
  When unsharing a user namespace we reduce our credentials to just what
  can be done in that user namespace.  This is a subset of the credentials
  we previously had.  Teach commit_creds to recognize this is a subset
  of the credentials we have had before and don't clear the dumpability flag.
  
  This allows an unprivileged  program to do:
  unshare(CLONE_NEWUSER);
  fd = open(/proc/self/uid_map, O_RDWR);
  
  Where previously opening the uid_map writable would fail because
  the the task had been made non-dumpable.
  
  Signed-off-by: Eric W. Biederman ebied...@xmission.com
 
  Acked-by: Serge Hallyn serge.hal...@canonical.com
 
  ---
   kernel/cred.c |   26 +-
   1 files changed, 25 insertions(+), 1 deletions(-)
  
  diff --git a/kernel/cred.c b/kernel/cred.c
  index 48cea3d..993a7ea41 100644
  --- a/kernel/cred.c
  +++ b/kernel/cred.c
  @@ -455,6 +455,30 @@ error_put:
 return ret;
   }
   
 
  Do you think we need to warn that this can only be used for
  commit_creds?  (i.e. if someone tried ot use this in some
  other context, the 'creds are subset of target ns is a child
  of current_ns' assumption would be wrong)
 
 This function should be a general test valid at any time.
 
 Except that I forgot the bit of the test that asks is the original cred
 the owner of the subset user namespace.

Ok, with that change that'll be fine :)

 I will respin this patch.

Cool, thanks.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Eric W. Biederman

When unsharing a user namespace we reduce our credentials to just what
can be done in that user namespace.  This is a subset of the credentials
we previously had.  Teach commit_creds to recognize this is a subset
of the credentials we have had before and don't clear the dumpability flag.

This allows an unprivileged  program to do:
unshare(CLONE_NEWUSER);
fd = open(/proc/self/uid_map, O_RDWR);

Where previously opening the uid_map writable would fail because
the the task had been made non-dumpable.

Signed-off-by: Eric W. Biederman ebied...@xmission.com
---
 kernel/cred.c |   27 ++-
 1 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/kernel/cred.c b/kernel/cred.c
index 48cea3d..709d521 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -455,6 +455,31 @@ error_put:
return ret;
 }
 
+static bool cred_cap_issubset(const struct cred *set, const struct cred 
*subset)
+{
+   const struct user_namespace *set_ns = set-user_ns;
+   const struct user_namespace *subset_ns = subset-user_ns;
+
+   /* If the two credentials are in the same user namespace see if
+* the capabilities of subset are a subset of set.
+*/
+   if (set_ns == subset_ns)
+   return cap_issubset(subset-cap_permitted, set-cap_permitted);
+
+   /* The credentials are in a different user namespaces
+* therefore one is a subset of the other only if a set is an
+* ancestor of subset and set-euid is owner of subset or one
+* of subsets ancestors.
+*/
+   for (;subset_ns != init_user_ns; subset_ns = subset_ns-parent) {
+   if ((set_ns == subset_ns-parent)  
+   uid_eq(subset_ns-owner, set-euid))
+   return true;
+   }
+
+   return false;
+}
+
 /**
  * commit_creds - Install new credentials upon the current task
  * @new: The credentials to be assigned
@@ -493,7 +518,7 @@ int commit_creds(struct cred *new)
!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)) {
+   !cred_cap_issubset(old, new)) {
if (task-mm)
set_dumpable(task-mm, suid_dumpable);
task-pdeath_signal = 0;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] userns: Add a more complete capability subset test to commit_creds

2012-12-14 Thread Serge E. Hallyn
Quoting Eric W. Biederman (ebied...@xmission.com):
 
 When unsharing a user namespace we reduce our credentials to just what
 can be done in that user namespace.  This is a subset of the credentials
 we previously had.  Teach commit_creds to recognize this is a subset
 of the credentials we have had before and don't clear the dumpability flag.
 
 This allows an unprivileged  program to do:
 unshare(CLONE_NEWUSER);
 fd = open(/proc/self/uid_map, O_RDWR);
 
 Where previously opening the uid_map writable would fail because
 the the task had been made non-dumpable.
 
 Signed-off-by: Eric W. Biederman ebied...@xmission.com

Acked-by: Serge Hallyn serge.hal...@canonical.com

 ---
  kernel/cred.c |   27 ++-
  1 files changed, 26 insertions(+), 1 deletions(-)
 
 diff --git a/kernel/cred.c b/kernel/cred.c
 index 48cea3d..709d521 100644
 --- a/kernel/cred.c
 +++ b/kernel/cred.c
 @@ -455,6 +455,31 @@ error_put:
   return ret;
  }
  
 +static bool cred_cap_issubset(const struct cred *set, const struct cred 
 *subset)
 +{
 + const struct user_namespace *set_ns = set-user_ns;
 + const struct user_namespace *subset_ns = subset-user_ns;
 +
 + /* If the two credentials are in the same user namespace see if
 +  * the capabilities of subset are a subset of set.
 +  */
 + if (set_ns == subset_ns)
 + return cap_issubset(subset-cap_permitted, set-cap_permitted);
 +
 + /* The credentials are in a different user namespaces
 +  * therefore one is a subset of the other only if a set is an
 +  * ancestor of subset and set-euid is owner of subset or one
 +  * of subsets ancestors.
 +  */
 + for (;subset_ns != init_user_ns; subset_ns = subset_ns-parent) {
 + if ((set_ns == subset_ns-parent)  
 + uid_eq(subset_ns-owner, set-euid))
 + return true;
 + }
 +
 + return false;
 +}
 +
  /**
   * commit_creds - Install new credentials upon the current task
   * @new: The credentials to be assigned
 @@ -493,7 +518,7 @@ int commit_creds(struct cred *new)
   !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)) {
 + !cred_cap_issubset(old, new)) {
   if (task-mm)
   set_dumpable(task-mm, suid_dumpable);
   task-pdeath_signal = 0;
 -- 
 1.7.5.4
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/