Skip to contentSkip to conversation

ioctl CAP_LINUX_IMMUTABLE is checked in the wrong namespace

PATCH NAK Marian Marinov 8 participants 31 messages Apr 29, 2014 – Apr 30, 2014 1 message not in the archive ext4 file system

lore
Share & tools
lore
#0 lore raw

Hello,
when using user namespaces I found a bug in the capability checks done by ioctl.

If someone tries to use chattr +i while in a different user namespace it will get the following:

ioctl(3, EXT2_IOC_SETFLAGS, 0x7fffa4fedacc) = -1 EPERM (Operation not permitted)

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

If you agree I can send patches for all filesystems.

I'm proposing the following patch:

---
 fs/ext4/ioctl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/ioctl.c +1 -1
index d011b69..25683d0 100644
@@ -265,7 +265,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 * This test looks nicer. Thanks to Pauline Middelink
                 */
                if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
-                       if (!capable(CAP_LINUX_IMMUTABLE))
+                       if (!ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE))
                                goto flags_out;
                }
 
Signature · 9 lines
1.8.4


-- 
Marian Marinov
Founder & CEO of 1H Ltd.
Jabber/GTalk: hackman-/[email protected]
ICQ: 7556201
Mobile: +359 886 660 270

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

No? Otherwise, pretty much every single use of capable() would be broken, not just this once instances in ext4/ioctl.c.

- Ted

#3 lore raw
In reply to a message not in the archive
Quoted 9 lines · Marian Marinov

Hello,
when using user namespaces I found a bug in the capability checks done by ioctl.

If someone tries to use chattr +i while in a different user namespace it will get the following:

ioctl(3, EXT2_IOC_SETFLAGS, 0x7fffa4fedacc) = -1 EPERM (Operation not permitted)

NAK. This is correct: you don't want users to be able to unshare(CLONE_NEWUSER) and then start playing with the immutable bit.

--Andy

maintainer
#4 lore raw
In reply to Marian Marinov
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

No? Otherwise, pretty much every single use of capable() would be broken, not just this once instances in ext4/ioctl.c.

- Ted

#5 lore raw
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

Quoted 8 lines

No? Otherwise, pretty much every single use of capable() would be broken, not just this once instances in ext4/ioctl.c.

- Ted
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

#6 lore raw
Quoted 31 lines · Serge Hallyn
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 7 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Marian

Quoted 9 lines
Quoted 8 lines

No? Otherwise, pretty much every single use of capable() would be broken, not just this once instances in ext4/ioctl.c.

- Ted
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

Signature · 5 lines
Marian Marinov
Founder & CEO of 1H Ltd.
Jabber/GTalk: hackman-/[email protected]
ICQ: 7556201
Mobile: +359 886 660 270
#7 lore raw
Quoted 36 lines · Marian Marinov
Quoted 35 lines · Serge Hallyn
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

Quoted 8 lines
Quoted 3 lines

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Right, and I think the two operations you're looking at seem sane to allow.

thanks,
-serge

#8 lore raw
Quoted 41 lines · Serge Hallyn
Quoted 40 lines · Marian Marinov
Quoted 38 lines · Serge Hallyn
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

Quoted 7 lines
Quoted 4 lines

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

---
 fs/ext4/ioctl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/ioctl.c +1 -1
index d011b69..9418634 100644
@@ -265,7 +265,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 * This test looks nicer. Thanks to Pauline Middelink
                 */
                if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
-                   if (!capable(CAP_LINUX_IMMUTABLE))
+                 if (!inode_capable(inode, CAP_LINUX_IMMUTABLE))
                                goto flags_out;
                }
 

---
1.8.4

Marian

Quoted 4 lines

thanks,
-serge

Signature · 5 lines
Marian Marinov
Founder & CEO of 1H Ltd.
Jabber/GTalk: hackman-/[email protected]
ICQ: 7556201
Mobile: +359 886 660 270
Acked-by
#9 lore raw
Quoted 45 lines · Marian Marinov
Quoted 44 lines · Serge Hallyn
Quoted 43 lines · Marian Marinov
Quoted 31 lines · Serge Hallyn
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 7 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

I agree that this is more sane.

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Sounds good, thanks.

Quoted 1 line
Quoted 35 lines
---
 fs/ext4/ioctl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ext4/ioctl.c +1 -2
index d011b69..9418634 100644
@@ -265,7 +265,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                 * This test looks nicer. Thanks to Pauline Middelink
                 */
                if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
-                   if (!capable(CAP_LINUX_IMMUTABLE))
+                 if (!inode_capable(inode, CAP_LINUX_IMMUTABLE))
                                goto flags_out;
                }
 
---

1.8.4

Marian

Quoted 4 lines

thanks,
-serge

Signature · 5 lines
Marian Marinov
Founder & CEO of 1H Ltd.
Jabber/GTalk: hackman-/[email protected]
ICQ: 7556201
Mobile: +359 886 660 270
Nacked-by NAK
#10 lore raw
Quoted 51 lines · Serge Hallyn
Quoted 50 lines · Marian Marinov
Quoted 48 lines · Serge Hallyn
Quoted 36 lines · Marian Marinov
Quoted 35 lines · Serge Hallyn
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

Quoted 8 lines
Quoted 3 lines

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Right, and I think the two operations you're looking at seem sane to allow.

Quoted 7 lines
Quoted 1 line

If you are ok with this patch, I will fix all file systems and send patches.

Sounds good, thanks.

Quoted 1 line

Wait, what?

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

maintainer
#11 lore raw
Quoted 7 lines · Andy Lutomirski

Wait, what?

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Quoted 5 lines

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

Right, but you can't set a mapping in a child namespace unless you have CAP_SETUID in the parent namespace, right? Otherwise user namespaces are completely broken from a security perspective, since inode_capable() could never do the right thing.

Personally, reading how user namespaces work, it makes the hair rise on the back of my neck. I'm not sure the concept works at all from a security perspective, but hey, I'm not using user namespaces, and some fool thought it was worth merging. :-)

- Ted

#12 lore raw
Quoted 8 lines · Theodore Ts'o
Quoted 7 lines · Andy Lutomirski

Wait, what?

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Quoted 8 lines
Quoted 5 lines

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

Right, but you can't set a mapping in a child namespace unless you have CAP_SETUID in the parent namespace, right?

Nope. You can't set a mapping for someone else's uid, but you can certainly map your own.

Quoted 3 lines

Otherwise user
namespaces are completely broken from a security perspective, since inode_capable() could never do the right thing.

I don't know what inode_capable's "right thing" is, but at least one of the existing callers is blatantly wrong. Patches coming shortly.

Quoted 5 lines

Personally, reading how user namespaces work, it makes the hair rise on the back of my neck. I'm not sure the concept works at all from a security perspective, but hey, I'm not using user namespaces, and some fool thought it was worth merging. :-)

I like them. I've also found quite a few serious bugs in them. So go figure :)

--Andy

#13 lore raw
In reply to Andy Lutomirski
Quoted 62 lines · Andy Lutomirski
Quoted 51 lines · Serge Hallyn
Quoted 50 lines · Marian Marinov
Quoted 48 lines · Serge Hallyn
Quoted 36 lines · Marian Marinov
Quoted 35 lines · Serge Hallyn
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

Quoted 8 lines
Quoted 3 lines

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Right, and I think the two operations you're looking at seem sane to allow.

Quoted 7 lines
Quoted 1 line

If you are ok with this patch, I will fix all file systems and send patches.

Sounds good, thanks.

Quoted 1 line

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

Marian

Quoted 5 lines
Signature · 5 lines
Marian Marinov
Founder & CEO of 1H Ltd.
Jabber/GTalk: hackman-/[email protected]
ICQ: 7556201
Mobile: +359 886 660 270
#14 lore raw
Quoted 105 lines · Marian Marinov
Quoted 88 lines · Andy Lutomirski
Quoted 75 lines · Serge Hallyn
Quoted 65 lines · Marian Marinov
Quoted 63 lines · Serge Hallyn
Quoted 59 lines · Marian Marinov
Quoted 42 lines · Serge Hallyn
Quoted 29 lines · Theodore Ts'o
Quoted 6 lines · Marian Marinov

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
        return ns_capable(&init_user_ns, cap);
}
Quoted 6 lines

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 9 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 6 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 7 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

Quoted 7 lines

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

--Andy

#15 lore raw
Quoted 114 lines · Andy Lutomirski
Quoted 105 lines · Marian Marinov
Quoted 88 lines · Andy Lutomirski
Quoted 75 lines · Serge Hallyn
Quoted 65 lines · Marian Marinov
Quoted 63 lines · Serge Hallyn
Quoted 59 lines · Marian Marinov
Quoted 42 lines · Serge Hallyn
Quoted 29 lines · Theodore Ts'o
Quoted 6 lines · Marian Marinov

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
        return ns_capable(&init_user_ns, cap);
}
Quoted 6 lines

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 9 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 6 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 7 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

Quoted 7 lines

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

Quoted 8 lines

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

--Andy

The most obvious problem I can think of with "do whatever" is that this will likely include mknod of char and block devices which you can then chown/chmod as you wish and use to access any devices on the system from an unprivileged container.
This can however be mitigated by using the devices cgroup controller.

You also probably wouldn't want any unprivileged user from the host to find a way to access that mounted filesytem but so long as you do the mount in a separate mountns and don't share uids between the host and the container, that should be fine too.

Signature · 3 lines
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com

_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

#16 lore raw
Quoted 122 lines · Stéphane Graber
Quoted 121 lines · Andy Lutomirski
Quoted 105 lines · Marian Marinov
Quoted 88 lines · Andy Lutomirski
Quoted 75 lines · Serge Hallyn
Quoted 65 lines · Marian Marinov
Quoted 63 lines · Serge Hallyn
Quoted 59 lines · Marian Marinov
Quoted 42 lines · Serge Hallyn
Quoted 29 lines · Theodore Ts'o
Quoted 6 lines · Marian Marinov

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
        return ns_capable(&init_user_ns, cap);
}
Quoted 6 lines

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 9 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 6 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 7 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

Quoted 7 lines

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

Quoted 7 lines
Quoted 1 line

--Andy

The most obvious problem I can think of with "do whatever" is that this will likely include mknod of char and block devices which you can then chown/chmod as you wish and use to access any devices on the system from an unprivileged container.
This can however be mitigated by using the devices cgroup controller.

Or 'nodev'. setuid/setgid may have the same problem, too.

Implementing something like this would also make CAP_DAC_READ_SEARCH and CAP_DAC_OVERRIDE work.

Arguably it should be impossible to mount such a thing in the first place without global privilege.

Quoted 5 lines

You also probably wouldn't want any unprivileged user from the host to find a way to access that mounted filesytem but so long as you do the mount in a separate mountns and don't share uids between the host and the container, that should be fine too.

This part should be a nonissue -- an unprivileged user who has the right uid owns the namespace anyway, so this is the least of your worries.

--Andy
_______________________________________________
Containers mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/containers

#17 lore raw
Quoted 145 lines · Andy Lutomirski
Quoted 122 lines · Stéphane Graber
Quoted 121 lines · Andy Lutomirski
Quoted 105 lines · Marian Marinov
Quoted 88 lines · Andy Lutomirski
Quoted 75 lines · Serge Hallyn
Quoted 65 lines · Marian Marinov
Quoted 63 lines · Serge Hallyn
Quoted 59 lines · Marian Marinov
Quoted 42 lines · Serge Hallyn
Quoted 29 lines · Theodore Ts'o
Quoted 6 lines · Marian Marinov

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
        return ns_capable(&init_user_ns, cap);
}
Quoted 6 lines

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 9 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 6 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 7 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

Quoted 7 lines

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

Quoted 7 lines
Quoted 1 line

--Andy

The most obvious problem I can think of with "do whatever" is that this will likely include mknod of char and block devices which you can then chown/chmod as you wish and use to access any devices on the system from an unprivileged container.
This can however be mitigated by using the devices cgroup controller.

Or 'nodev'. setuid/setgid may have the same problem, too.

Implementing something like this would also make CAP_DAC_READ_SEARCH and CAP_DAC_OVERRIDE work.

Arguably it should be impossible to mount such a thing in the first place without global privilege.

Quoted 5 lines

You also probably wouldn't want any unprivileged user from the host to find a way to access that mounted filesytem but so long as you do the mount in a separate mountns and don't share uids between the host and the container, that should be fine too.

Quoted 5 lines

This part should be a nonissue -- an unprivileged user who has the right uid owns the namespace anyway, so this is the least of your worries.

--Andy

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

So that's restricting slightly what "do whatever" would do in this case.

Signature · 3 lines
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com

_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

#18 lore raw
Quoted 152 lines · Stéphane Graber
Quoted 145 lines · Andy Lutomirski
Quoted 122 lines · Stéphane Graber
Quoted 121 lines · Andy Lutomirski
Quoted 105 lines · Marian Marinov
Quoted 88 lines · Andy Lutomirski
Quoted 75 lines · Serge Hallyn
Quoted 65 lines · Marian Marinov
Quoted 63 lines · Serge Hallyn
Quoted 59 lines · Marian Marinov
Quoted 42 lines · Serge Hallyn
Quoted 29 lines · Theodore Ts'o
Quoted 6 lines · Marian Marinov

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
         return ns_capable(&init_user_ns, cap);
}
Quoted 6 lines

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 9 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 6 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 7 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

Quoted 7 lines

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

Quoted 7 lines
Quoted 1 line

--Andy

The most obvious problem I can think of with "do whatever" is that this will likely include mknod of char and block devices which you can then chown/chmod as you wish and use to access any devices on the system from an unprivileged container.
This can however be mitigated by using the devices cgroup controller.

Or 'nodev'. setuid/setgid may have the same problem, too.

Implementing something like this would also make CAP_DAC_READ_SEARCH and CAP_DAC_OVERRIDE work.

Arguably it should be impossible to mount such a thing in the first place without global privilege.

Quoted 5 lines

You also probably wouldn't want any unprivileged user from the host to find a way to access that mounted filesytem but so long as you do the mount in a separate mountns and don't share uids between the host and the container, that should be fine too.

Quoted 5 lines

This part should be a nonissue -- an unprivileged user who has the right uid owns the namespace anyway, so this is the least of your worries.

--Andy

Quoted 8 lines

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

So that's restricting slightly what "do whatever" would do in this case.

In my case I give an LVM volume to each container and limit the container to only this block device using the devices cgroup.
So the inode_capable() fix worked like a charm for me.
The container can not see any filesystem other then its own.
And I have another patch for my kernel that prohibits setns from cgroup other then / which prevents programs from the container from getting out. clone() can be used to create new namespaces but can not be used to attach to already created namespaces.

Marian

Signature · 5 lines
Marian Marinov
Founder & CEO of 1H Ltd.
Jabber/GTalk: hackman-/[email protected]
ICQ: 7556201
Mobile: +359 886 660 270
#19 lore raw
Quoted 200 lines · Marian Marinov
Quoted 190 lines · Stéphane Graber
Quoted 181 lines · Andy Lutomirski
Quoted 153 lines · Stéphane Graber
Quoted 151 lines · Andy Lutomirski
Quoted 134 lines · Marian Marinov
Quoted 113 lines · Andy Lutomirski
Quoted 92 lines · Serge Hallyn
Quoted 79 lines · Marian Marinov
Quoted 76 lines · Serge Hallyn
Quoted 70 lines · Marian Marinov
Quoted 56 lines · Serge Hallyn
Quoted 40 lines · Theodore Ts'o

On Tue, Apr 29, 2014 at 04:49:14PM +0300, Marian Marinov wrote:

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)
{
return ns_capable(&init_user_ns, cap);
}
EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and
I
can't imagine any use case, where user namespaces are in
effect,
where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the
subject.

The patch by Marian is wrong. Anyone can do
'clone(CLONE_NEWUSER)',
setuid(0), execve, and end up satisfying
'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

Quoted 5 lines

So NACK to that particular patch. I'm not sure, but IIUC it should
be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 7 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 8 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Inodes aren't owned by user namespaces; they're owned by users. And any
user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Quoted 4 lines

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this
gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able
to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

Quoted 6 lines

The first solution got its user namespace from the currently running process
and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

Quoted 8 lines
Quoted 1 line

--Andy

The most obvious problem I can think of with "do whatever" is that this will likely include mknod of char and block devices which you can then chown/chmod as you wish and use to access any devices on the system from an unprivileged container.
This can however be mitigated by using the devices cgroup controller.

Or 'nodev'. setuid/setgid may have the same problem, too.

Implementing something like this would also make CAP_DAC_READ_SEARCH and CAP_DAC_OVERRIDE work.

Arguably it should be impossible to mount such a thing in the first place without global privilege.

Quoted 5 lines

You also probably wouldn't want any unprivileged user from the host to find a way to access that mounted filesytem but so long as you do the mount in a separate mountns and don't share uids between the host and the container, that should be fine too.

Quoted 5 lines

This part should be a nonissue -- an unprivileged user who has the right uid owns the namespace anyway, so this is the least of your worries.

--Andy

Quoted 8 lines

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

So that's restricting slightly what "do whatever" would do in this case.

Quoted 8 lines

In my case I give an LVM volume to each container and limit the container to only this block device using the devices cgroup.
So the inode_capable() fix worked like a charm for me.
The container can not see any filesystem other then its own.
And I have another patch for my kernel that prohibits setns from cgroup other then / which prevents programs from the container from getting out. clone() can be used to create new namespaces but can not be used to attach to already created namespaces.

Doesn't matter -- the risk here is that an attacker outside the namespace can get an fd that points to a directory in the namespace. SCM_RIGHTS would be the major vector.

--Andy
_______________________________________________
Containers mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/containers

#20 lore raw
In reply to Stéphane Graber
Quoted 150 lines · Stéphane Graber
Quoted 149 lines · Andy Lutomirski
Quoted 122 lines · Stéphane Graber
Quoted 121 lines · Andy Lutomirski
Quoted 105 lines · Marian Marinov
Quoted 88 lines · Andy Lutomirski
Quoted 75 lines · Serge Hallyn
Quoted 65 lines · Marian Marinov
Quoted 63 lines · Serge Hallyn
Quoted 59 lines · Marian Marinov
Quoted 42 lines · Serge Hallyn
Quoted 29 lines · Theodore Ts'o
Quoted 6 lines · Marian Marinov

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

{
        return ns_capable(&init_user_ns, cap);
}
Quoted 6 lines

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 9 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 6 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 7 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

Quoted 7 lines

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

Quoted 7 lines
Quoted 1 line

--Andy

The most obvious problem I can think of with "do whatever" is that this will likely include mknod of char and block devices which you can then chown/chmod as you wish and use to access any devices on the system from an unprivileged container.
This can however be mitigated by using the devices cgroup controller.

Or 'nodev'. setuid/setgid may have the same problem, too.

Implementing something like this would also make CAP_DAC_READ_SEARCH and CAP_DAC_OVERRIDE work.

Arguably it should be impossible to mount such a thing in the first place without global privilege.

Quoted 5 lines

You also probably wouldn't want any unprivileged user from the host to find a way to access that mounted filesytem but so long as you do the mount in a separate mountns and don't share uids between the host and the container, that should be fine too.

This part should be a nonissue -- an unprivileged user who has the right uid owns the namespace anyway, so this is the least of your worries.

Quoted 7 lines
Quoted 1 line

--Andy

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

I feel like that's too fragile. I'd rather add a rule that one of these filesystems always acts like it's nosuid unless you're inside a user namespace that matches fs_owner_uid.

Maybe even that is too weird. How about setuid, setgid, and fcaps only work on mounts that are in mount namespaces that are owned by the current user namespace or one of its parents? IOW, a struct mount is only trusted if mnt->mnt_ns->user_ns == current user ns or one of its parents?

Untrusted mounts would act like they are nosuid,nodev. Someone can try to figure out a safe way to relax nodev at some point.

--Andy
_______________________________________________
Containers mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/containers

#21 lore raw
Quoted 153 lines · Andy Lutomirski
Quoted 152 lines · Stéphane Graber
Quoted 150 lines · Andy Lutomirski
Quoted 122 lines · Stéphane Graber
Quoted 121 lines · Andy Lutomirski
Quoted 105 lines · Marian Marinov
Quoted 88 lines · Andy Lutomirski
Quoted 75 lines · Serge Hallyn
Quoted 65 lines · Marian Marinov
Quoted 63 lines · Serge Hallyn
Quoted 59 lines · Marian Marinov
Quoted 42 lines · Serge Hallyn
Quoted 35 lines · Theodore Ts'o

On Tue, Apr 29, 2014 at 04:49:14PM +0300, Marian Marinov wrote:

I'm proposing a fix to this, by replacing the
capable(CAP_LINUX_IMMUTABLE)
check with ns_capable(current_cred()->user_ns,
CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior
capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior
capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is
available on the
* assumption that it's about to be used.
*/
bool capable(int cap)
{
return ns_capable(&init_user_ns, cap);
}
EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I
can't imagine any use case, where user namespaces are in effect,
where
using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

Quoted 9 lines

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns,
CAP_SYS_IMMUTABLE)' by definition.

So NACK to that particular patch. I'm not sure, but IIUC it should be
safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Quoted 6 lines
Quoted 2 lines

Right, and I think the two operations you're looking at seem sane to allow.

If you are ok with this patch, I will fix all file systems and send patches.

Quoted 7 lines

Sounds good, thanks.

Quoted 1 line

Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/[email protected]>

Wait, what?

Quoted 7 lines

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

The problem I'm trying to solve is this:

container with its own user namespace and CAP_SYS_IMMUTABLE should be able to use chattr on all files witch this container has access to.

Unfortunately with the capable(CAP_SYS_IMMUTABLE) check this is not working.

Quoted 7 lines

With the proposed two fixes CAP_SYS_IMMUTABLE started working in the container.

The first solution got its user namespace from the currently running process and the second gets its user namespace from the currently opened inode.

So what would be the best solution in this case?

I'd suggest adding a mount option like fs_owner_uid that names a uid that owns, in the sense of having unlimited access to, a filesystem. Then anyone with caps on a namespace owned by that uid could do whatever.

Eric?

Quoted 7 lines
Quoted 1 line

--Andy

The most obvious problem I can think of with "do whatever" is that this will likely include mknod of char and block devices which you can then chown/chmod as you wish and use to access any devices on the system from an unprivileged container.
This can however be mitigated by using the devices cgroup controller.

Or 'nodev'. setuid/setgid may have the same problem, too.

Implementing something like this would also make CAP_DAC_READ_SEARCH and CAP_DAC_OVERRIDE work.

Arguably it should be impossible to mount such a thing in the first place without global privilege.

Quoted 5 lines

You also probably wouldn't want any unprivileged user from the host to find a way to access that mounted filesytem but so long as you do the mount in a separate mountns and don't share uids between the host and the container, that should be fine too.

This part should be a nonissue -- an unprivileged user who has the right uid owns the namespace anyway, so this is the least of your worries.

--Andy

Quoted 7 lines
Quoted 5 lines

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

I feel like that's too fragile. I'd rather add a rule that one of

yeah I don't wnat to rush something like that. I'd rather stash the userns of the task which did the mounting and check against that. Note that would make it worthless unless and until we allowed mounting from non-init userns, but then we can only claim "our fs superblock readers suck and therefore containers can't mount an fs" so long before we start to feel some shame and audit them...

Quoted 17 lines

these filesystems always acts like it's nosuid unless you're inside a user namespace that matches fs_owner_uid.

Maybe even that is too weird. How about setuid, setgid, and fcaps only work on mounts that are in mount namespaces that are owned by the current user namespace or one of its parents? IOW, a struct mount is only trusted if mnt->mnt_ns->user_ns == current user ns or one of its parents?

Untrusted mounts would act like they are nosuid,nodev. Someone can try to figure out a safe way to relax nodev at some point.

--Andy
_______________________________________________
Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers

#22 lore raw
Quoted 7 lines · Serge Hallyn
Quoted 6 lines · Andy Lutomirski
Quoted 5 lines

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

Quoted 20 lines
Quoted 1 line

I feel like that's too fragile. I'd rather add a rule that one of

yeah I don't wnat to rush something like that. I'd rather stash the userns of the task which did the mounting and check against that. Note that would make it worthless unless and until we allowed mounting from non-init userns, but then we can only claim "our fs superblock readers suck and therefore containers can't mount an fs" so long before we start to feel some shame and audit them...

Quoted 11 lines

these filesystems always acts like it's nosuid unless you're inside a user namespace that matches fs_owner_uid.

Maybe even that is too weird. How about setuid, setgid, and fcaps only work on mounts that are in mount namespaces that are owned by the current user namespace or one of its parents? IOW, a struct mount is only trusted if mnt->mnt_ns->user_ns == current user ns or one of its parents?

Untrusted mounts would act like they are nosuid,nodev. Someone can try to figure out a safe way to relax nodev at some point.

Do you like this variant? We could add a way for global root to mount an fs on behalf of a userns. I'd rather this be more explicit than just mounting it in a mount ns owned by the user namespace, though.

--Andy

#23 lore raw
Quoted 26 lines · Andy Lutomirski
Quoted 25 lines · Serge Hallyn
Quoted 7 lines · Andy Lutomirski
Quoted 5 lines

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

I feel like that's too fragile. I'd rather add a rule that one of

yeah I don't wnat to rush something like that. I'd rather stash the userns of the task which did the mounting and check against that. Note that would make it worthless unless and until we allowed mounting from non-init userns, but then we can only claim "our fs superblock readers suck and therefore containers can't mount an fs" so long before we start to feel some shame and audit them...

Quoted 9 lines

these filesystems always acts like it's nosuid unless you're inside a user namespace that matches fs_owner_uid.

Maybe even that is too weird. How about setuid, setgid, and fcaps only work on mounts that are in mount namespaces that are owned by the current user namespace or one of its parents? IOW, a struct mount is only trusted if mnt->mnt_ns->user_ns == current user ns or one of its parents?

Quoted 6 lines
Quoted 2 lines
Quoted 2 lines

Untrusted mounts would act like they are nosuid,nodev. Someone can try to figure out a safe way to relax nodev at some point.

Do you like this variant? We could add a way for global root to mount an fs on behalf of a userns. I'd rather this be more explicit than just mounting it in a mount ns owned by the user namespace, though.

I'm missing something. Which mnt are you talking about? A user can just clone a new userns and then clone(CLONE_NEWNS) to get a set of mounts owned by himself... We need to get a mnt (or a cred or straight to a userns) tied to the first mount of the superblock, istm.

-serge

#24 lore raw
Quoted 30 lines · Serge Hallyn
Quoted 29 lines · Andy Lutomirski
Quoted 27 lines · Serge Hallyn
Quoted 7 lines · Andy Lutomirski
Quoted 5 lines

It should be a nonissue so long as we make sure that a file owned by a uid outside the scope of the container may not be changed even though fs_owner_uid is set. Otherwise, it's just a matter of chmod +S on say a shell and anyone who can see the fs from the host will be getting a root shell (assuming said file is owned by the host's uid 0).

I feel like that's too fragile. I'd rather add a rule that one of

yeah I don't wnat to rush something like that. I'd rather stash the userns of the task which did the mounting and check against that. Note that would make it worthless unless and until we allowed mounting from non-init userns, but then we can only claim "our fs superblock readers suck and therefore containers can't mount an fs" so long before we start to feel some shame and audit them...

Quoted 11 lines

these filesystems always acts like it's nosuid unless you're inside a user namespace that matches fs_owner_uid.

Maybe even that is too weird. How about setuid, setgid, and fcaps only work on mounts that are in mount namespaces that are owned by the current user namespace or one of its parents? IOW, a struct mount is only trusted if mnt->mnt_ns->user_ns == current user ns or one of its parents?

Untrusted mounts would act like they are nosuid,nodev. Someone can try to figure out a safe way to relax nodev at some point.

Quoted 8 lines
Quoted 3 lines

Do you like this variant? We could add a way for global root to mount an fs on behalf of a userns. I'd rather this be more explicit than just mounting it in a mount ns owned by the user namespace, though.

I'm missing something. Which mnt are you talking about? A user can just clone a new userns and then clone(CLONE_NEWNS) to get a set of mounts owned by himself... We need to get a mnt (or a cred or straight to a userns) tied to the first mount of the superblock, istm.

Sure, but then that user is the only user that ends up trusting the mount. This could end up being surprising, though -- it would be weird for a bind mount of an implicitly nosuid mount to end up not being nosuid as seen by the mounter.

This still feels a bit overcomplicated. Grr. I do like that idea that, if someone creates a tmpfs mount, sticks a setuid file in it, and hands someone outside the namespace an fd to the mount, that the file won't be setuid as seen from outside. This will make using the same uids in different containers a lot safer, although it still won't really be safe.

Another wart: chroot on a directory in someone else's mount namespace works, I think. That just seems wrong, although I don't immediately see how it's a problem.

--Andy

#25 lore raw
In reply to Andy Lutomirski
Quoted 60 lines · Andy Lutomirski
Quoted 51 lines · Serge Hallyn
Quoted 50 lines · Marian Marinov
Quoted 48 lines · Serge Hallyn
Quoted 36 lines · Marian Marinov
Quoted 35 lines · Serge Hallyn
Quoted 18 lines · Theodore Ts'o
Quoted 3 lines · Marian Marinov

I'm proposing a fix to this, by replacing the capable(CAP_LINUX_IMMUTABLE) check with ns_capable(current_cred()->user_ns, CAP_LINUX_IMMUTABLE).

Um, wouldn't it be better to simply fix the capable() function?

/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
* Return true if the current task has the given superior capability currently
* available for use, false if not.
*
* This sets PF_SUPERPRIV on the task if the capability is available on the
* assumption that it's about to be used.
*/
bool capable(int cap)

Quoted 8 lines
{
	return ns_capable(&init_user_ns, cap);
}

EXPORT_SYMBOL(capable);

The documentation states that it is for "the current task", and I can't imagine any use case, where user namespaces are in effect, where using init_user_ns would ever make sense.

the init_user_ns represents the user_ns owning the object, not the subject.

The patch by Marian is wrong. Anyone can do 'clone(CLONE_NEWUSER)', setuid(0), execve, and end up satisfying 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' by definition.

Quoted 8 lines
Quoted 3 lines

So NACK to that particular patch. I'm not sure, but IIUC it should be safe to check against the userns owning the inode?

So what you are proposing is to replace 'ns_capable(current_cred()->userns, CAP_SYS_IMMUTABLE)' with 'inode_capable(inode, CAP_SYS_IMMUTABLE)' ?

I agree that this is more sane.

Right, and I think the two operations you're looking at seem sane to allow.

Quoted 7 lines
Quoted 1 line

If you are ok with this patch, I will fix all file systems and send patches.

Sounds good, thanks.

Quoted 1 line
Quoted 7 lines

Wait, what?

Inodes aren't owned by user namespaces; they're owned by users. And any user can arrange to have a user namespace in which they pass an inode_capable check on any inode that they own.

Presumably there's a reason that CAP_SYS_IMMUTABLE is needed. If this

Sigh, yeah... I just dont' understand what it is. But you're right.

Quoted 4 lines

gets merged, then it would be better to just drop CAP_SYS_IMMUTABLE entirely.

I forget the details, but there was another case where I wanted to have the userns which 'owns' the whole fs available. I guess we'd have to check against that instead of using inode_capable.

-serge

#26 lore raw
Quoted 3 lines · Serge Hallyn

I forget the details, but there was another case where I wanted to have the userns which 'owns' the whole fs available. I guess we'd have to check against that instead of using inode_capable.

Yes, that sounds right.

And *please* tell me that that under no circumstances can anyone other than root@init_user_ns is allowed to use mknod....

- Ted

maintainer
#27 lore raw
In reply to Serge Hallyn
Quoted 3 lines · Serge Hallyn

I forget the details, but there was another case where I wanted to have the userns which 'owns' the whole fs available. I guess we'd have to check against that instead of using inode_capable.

Yes, that sounds right.

And *please* tell me that that under no circumstances can anyone other than root@init_user_ns is allowed to use mknod....

- Ted

#28 lore raw
Quoted 9 lines · Theodore Ts'o
Quoted 3 lines · Serge Hallyn

I forget the details, but there was another case where I wanted to have the userns which 'owns' the whole fs available. I guess we'd have to check against that instead of using inode_capable.

Yes, that sounds right.

And *please* tell me that that under no circumstances can anyone other than root@init_user_ns is allowed to use mknod....

I haven't read the code, but I tried it the other day, and I got
-EPERM. So we're okay for now. (Well, other than the issue I just
sent to [email protected], but that's not quite the same thing.)

--Andy

#29 lore raw
In reply to Theodore Ts'o
Quoted 9 lines · Theodore Ts'o
Quoted 3 lines · Serge Hallyn

I forget the details, but there was another case where I wanted to have the userns which 'owns' the whole fs available. I guess we'd have to check against that instead of using inode_capable.

Yes, that sounds right.

And *please* tell me that that under no circumstances can anyone other than root@init_user_ns is allowed to use mknod....

That's the case. We've considered making exceptions for things like /dev/null, but in practice bind-mounting devices from the host has worked out just fine.

#30 lore raw
In reply to Theodore Ts'o
Quoted 9 lines · Theodore Ts'o
Quoted 3 lines · Serge Hallyn

I forget the details, but there was another case where I wanted to have the userns which 'owns' the whole fs available. I guess we'd have to check against that instead of using inode_capable.

Yes, that sounds right.

And *please* tell me that that under no circumstances can anyone other than root@init_user_ns is allowed to use mknod....

Nope. mknod not allowed. capable(CAP_MKNOD) is required is required and I can't see any reason to change that.

As a rule of thumb, the only additional actions allowed in a user namespace above and beyond what an ordinary unpriviliged user would be allowed to do are those things which we only don't allow because they could confuse a setuid root executable.

If we ever allow the creation of immutable files by unprivileged users those files would at least have to be kept completely separate from the files the global root encounters (aka a disjoint mount namespace).

I do not currently see a path to safely using immutable files with just user namespace root permission.

Eric

#31 lore raw
Quoted 21 lines · Eric W. Biederman
Quoted 9 lines · Theodore Ts'o
Quoted 3 lines · Serge Hallyn

I forget the details, but there was another case where I wanted to have the userns which 'owns' the whole fs available. I guess we'd have to check against that instead of using inode_capable.

Yes, that sounds right.

And *please* tell me that that under no circumstances can anyone other than root@init_user_ns is allowed to use mknod....

Nope. mknod not allowed. capable(CAP_MKNOD) is required is required and I can't see any reason to change that.

As a rule of thumb, the only additional actions allowed in a user namespace above and beyond what an ordinary unpriviliged user would be allowed to do are those things which we only don't allow because they could confuse a setuid root executable.

Quoted 6 lines

If we ever allow the creation of immutable files by unprivileged users those files would at least have to be kept completely separate from the files the global root encounters (aka a disjoint mount namespace).

I do not currently see a path to safely using immutable files with just user namespace root permission.

It's very far off, but I think the path is:

1. at first mount of a blockdev, note the cred (or just userns) which mounted it
2. work on auditing superblock readers so we can start allowing some blockdev mounts in user namespaces :)
3. check for privilege against the userns owning a superblock

-serge