Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.19-rc3 next-20180913]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180915-051650
config: i386-tinyconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386 

All errors (new ones prefixed by >>):

   kernel/cred.o: In function `commit_creds':
>> cred.c:(.text+0x1ae): undefined reference to `get_net_ns_by_pid'

---
0-DAY kernel test infrastructureOpen Source Technology Center
https://lists.01.org/pipermail/kbuild-all   Intel Corporation


.config.gz
Description: application/gzip


Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.19-rc3 next-20180913]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180915-051650
config: i386-tinyconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386 

All errors (new ones prefixed by >>):

   kernel/cred.o: In function `commit_creds':
>> cred.c:(.text+0x1ae): undefined reference to `get_net_ns_by_pid'

---
0-DAY kernel test infrastructureOpen Source Technology Center
https://lists.01.org/pipermail/kbuild-all   Intel Corporation


.config.gz
Description: application/gzip


Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread Jann Horn
On Fri, Sep 14, 2018 at 1:14 PM My Name <18650033...@163.com> wrote:
> Adversaries often attack the Linux kernel via using
> commit_creds(prepare_kernel_cred(0)) to submit ROOT
> credential for the purpose of privilege escalation.
> For processes inside the Linux container, the above
> approach also works, because the container and the
> host share the same Linux kernel. Therefore, we en-
> force a check in commit_creds() before updating the
> cred of the caller process. If the process is insi-
> de a container (judging from the Namespace ID) and
> try to submit credentials with higher privileges t-
> han current (judging from the uid, gid, and cap_bset
> in the new cred), we will stop the modification. We
> consider that if the namespace ID of the process is
> different from the init Namespace ID (enumed in /i-
> nclude/linux/proc_ns.h), the process is inside a c-
> ontainer. And if the uid/gid in the new cred is sm-
> aller or the cap_bset (capability bounding set) in
> the new cred is larger, it may be a privilege esca-
> lation operation.

You only sent this patch to the LKML list without CC'ing anyone.
People are unlikely to see your patches this way; you may want to, for
example, CC the kernel-hardening list and people who have touched the
files your patch changes in the past. More information on this is at
https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#select-the-recipients-for-your-patch
.

You sent five different versions of this patch; when you send multiple
versions of a patch, please ensure that the subject line contains the
version of the patch, as described in
https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html
.

I also disagree with the fundamental approach taken in your patch; in
my opinion, it is pointless to attempt to prevent kernel exploitation
by restricting usage of one specific function.

> Signed-off-by: Xin Lin <18650033...@163.com>
> ---
>  kernel/cred.c | 24 
>  1 file changed, 24 insertions(+)
>
> diff --git a/kernel/cred.c b/kernel/cred.c
> index ecf0365..b9a313d 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -19,6 +19,12 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
> +#include "../fs/mount.h"
> +#include 
> +#include 
> +#include 
>
>  #if 0
>  #define kdebug(FMT, ...)   \
> @@ -33,6 +39,8 @@ do {
>   \
>  } while (0)
>  #endif
>
> +bool flag = true;
> +static struct net *initnet;
>  static struct kmem_cache *cred_jar;
>
>  /* init to 2 - one for init_task, one to ensure it is never freed */
> @@ -425,6 +433,22 @@ int commit_creds(struct cred *new)
> struct task_struct *task = current;
> const struct cred *old = task->real_cred;
>
> +   if (flag) {
> +   initnet = get_net_ns_by_pid(1);
> +   flag = false;
> +   }
> +   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
> +   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
> +   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
> +   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
> +   task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
> +   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
> +   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
> +   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
> +   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
> +   return 0;
> +   }
> +
> kdebug("commit_creds(%p{%d,%d})", new,
>atomic_read(>usage),
>read_cred_subscribers(new));
> --
> 2.7.4
>
>
>


Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread Jann Horn
On Fri, Sep 14, 2018 at 1:14 PM My Name <18650033...@163.com> wrote:
> Adversaries often attack the Linux kernel via using
> commit_creds(prepare_kernel_cred(0)) to submit ROOT
> credential for the purpose of privilege escalation.
> For processes inside the Linux container, the above
> approach also works, because the container and the
> host share the same Linux kernel. Therefore, we en-
> force a check in commit_creds() before updating the
> cred of the caller process. If the process is insi-
> de a container (judging from the Namespace ID) and
> try to submit credentials with higher privileges t-
> han current (judging from the uid, gid, and cap_bset
> in the new cred), we will stop the modification. We
> consider that if the namespace ID of the process is
> different from the init Namespace ID (enumed in /i-
> nclude/linux/proc_ns.h), the process is inside a c-
> ontainer. And if the uid/gid in the new cred is sm-
> aller or the cap_bset (capability bounding set) in
> the new cred is larger, it may be a privilege esca-
> lation operation.

You only sent this patch to the LKML list without CC'ing anyone.
People are unlikely to see your patches this way; you may want to, for
example, CC the kernel-hardening list and people who have touched the
files your patch changes in the past. More information on this is at
https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#select-the-recipients-for-your-patch
.

You sent five different versions of this patch; when you send multiple
versions of a patch, please ensure that the subject line contains the
version of the patch, as described in
https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html
.

I also disagree with the fundamental approach taken in your patch; in
my opinion, it is pointless to attempt to prevent kernel exploitation
by restricting usage of one specific function.

> Signed-off-by: Xin Lin <18650033...@163.com>
> ---
>  kernel/cred.c | 24 
>  1 file changed, 24 insertions(+)
>
> diff --git a/kernel/cred.c b/kernel/cred.c
> index ecf0365..b9a313d 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -19,6 +19,12 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
> +#include "../fs/mount.h"
> +#include 
> +#include 
> +#include 
>
>  #if 0
>  #define kdebug(FMT, ...)   \
> @@ -33,6 +39,8 @@ do {
>   \
>  } while (0)
>  #endif
>
> +bool flag = true;
> +static struct net *initnet;
>  static struct kmem_cache *cred_jar;
>
>  /* init to 2 - one for init_task, one to ensure it is never freed */
> @@ -425,6 +433,22 @@ int commit_creds(struct cred *new)
> struct task_struct *task = current;
> const struct cred *old = task->real_cred;
>
> +   if (flag) {
> +   initnet = get_net_ns_by_pid(1);
> +   flag = false;
> +   }
> +   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
> +   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
> +   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
> +   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
> +   task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
> +   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
> +   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
> +   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
> +   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
> +   return 0;
> +   }
> +
> kdebug("commit_creds(%p{%d,%d})", new,
>atomic_read(>usage),
>read_cred_subscribers(new));
> --
> 2.7.4
>
>
>


[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..b9a313d 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -33,6 +39,8 @@ do {  
\
 } while (0)
 #endif
 
+bool flag = true;
+static struct net *initnet;
 static struct kmem_cache *cred_jar;
 
 /* init to 2 - one for init_task, one to ensure it is never freed */
@@ -425,6 +433,22 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (flag) {
+   initnet = get_net_ns_by_pid(1);
+   flag = false;
+   }
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4




[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..b9a313d 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -33,6 +39,8 @@ do {  
\
 } while (0)
 #endif
 
+bool flag = true;
+static struct net *initnet;
 static struct kmem_cache *cred_jar;
 
 /* init to 2 - one for init_task, one to ensure it is never freed */
@@ -425,6 +433,22 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (flag) {
+   initnet = get_net_ns_by_pid(1);
+   flag = false;
+   }
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4




Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.19-rc3 next-20180913]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180914-164803
config: ia64-allnoconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 8.1.0
reproduce:
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=8.1.0 make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

   kernel/cred.c: In function 'commit_creds':
   kernel/cred.c:439:40: error: 'PROC_UTS_INIT_INO' undeclared (first use in 
this function)
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   kernel/cred.c:439:40: note: each undeclared identifier is reported only once 
for each function it appears in
   kernel/cred.c:440:36: error: 'PROC_IPC_INIT_INO' undeclared (first use in 
this function)
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   ^
   kernel/cred.c:442:49: error: 'PROC_PID_INIT_INO' undeclared (first use in 
this function)
 task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
^
   kernel/cred.c:444:27: error: 'PROC_USER_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_EVENT_SID'?
 old->user_ns->ns.inum != PROC_USER_INIT_INO ||
  ^~
  PROC_EVENT_SID
>> kernel/cred.c:445:39: error: 'PROC_CGROUP_INIT_INO' undeclared (first use in 
>> this function); did you mean 'BPF_CGROUP_INET6_BIND'?
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
  ^~~~
  BPF_CGROUP_INET6_BIND

vim +445 kernel/cred.c

   415  
   416  /**
   417   * commit_creds - Install new credentials upon the current task
   418   * @new: The credentials to be assigned
   419   *
   420   * Install a new set of credentials to the current task, using RCU to 
replace
   421   * the old set.  Both the objective and the subjective credentials 
pointers are
   422   * updated.  This function may not be called if the subjective 
credentials are
   423   * in an overridden state.
   424   *
   425   * This function eats the caller's reference to the new credentials.
   426   *
   427   * Always returns 0 thus allowing this function to be tail-called at 
the end
   428   * of, say, sys_setgid().
   429   */
   430  int commit_creds(struct cred *new)
   431  {
   432  struct task_struct *task = current;
   433  const struct cred *old = task->real_cred;
   434  
   435  if (flag) {
   436  initnet = get_net_ns_by_pid(1);
   437  flag = false;
   438  }
   439  if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   440  task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   441  task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
 > 442  task->nsproxy->pid_ns_for_children->ns.inum != 
 > PROC_PID_INIT_INO ||
   443  task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
   444  old->user_ns->ns.inum != PROC_USER_INIT_INO ||
 > 445  task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
   446  if (new->uid.val < old->uid.val || new->gid.val < 
old->gid.val
   447  || new->cap_bset.cap[0] > old->cap_bset.cap[0])
   448  return 0;
   449  }
   450  
   451  kdebug("commit_creds(%p{%d,%d})", new,
   452 atomic_read(>usage),
   453 read_cred_subscribers(new));
   454  
   455  BUG_ON(task->cred != old);
   456  #ifdef CONFIG_DEBUG_CREDENTIALS
   457  BUG_ON(read_cred_subscribers(old) < 2);
   458  validate_creds(old);
   459  validate_creds(new);
   460  #endif
   461  BUG_ON(atomic_read(>usage) < 1);
   462  
   463  get_cred(new); /* we will require a ref for the subj creds too 
*/
   464  
   465  /* dumpability changes */
   466  if (!uid_eq(old->euid, new->euid) ||
   467  !gid_eq(old->egid, new->egid) ||
   468  !uid_eq(old->fsuid, new->fsuid) ||
   469  !gid_eq(old->fsgid, new->fsgid) ||
   470  !cred_cap_issubset(old, new)) {
   471  if (task->mm)
   472  set_dumpable(task->mm, suid_dumpable);
   473  task->pdeath_signal = 0;
   474  

Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.19-rc3 next-20180913]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180914-164803
config: ia64-allnoconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 8.1.0
reproduce:
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=8.1.0 make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

   kernel/cred.c: In function 'commit_creds':
   kernel/cred.c:439:40: error: 'PROC_UTS_INIT_INO' undeclared (first use in 
this function)
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   kernel/cred.c:439:40: note: each undeclared identifier is reported only once 
for each function it appears in
   kernel/cred.c:440:36: error: 'PROC_IPC_INIT_INO' undeclared (first use in 
this function)
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   ^
   kernel/cred.c:442:49: error: 'PROC_PID_INIT_INO' undeclared (first use in 
this function)
 task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
^
   kernel/cred.c:444:27: error: 'PROC_USER_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_EVENT_SID'?
 old->user_ns->ns.inum != PROC_USER_INIT_INO ||
  ^~
  PROC_EVENT_SID
>> kernel/cred.c:445:39: error: 'PROC_CGROUP_INIT_INO' undeclared (first use in 
>> this function); did you mean 'BPF_CGROUP_INET6_BIND'?
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
  ^~~~
  BPF_CGROUP_INET6_BIND

vim +445 kernel/cred.c

   415  
   416  /**
   417   * commit_creds - Install new credentials upon the current task
   418   * @new: The credentials to be assigned
   419   *
   420   * Install a new set of credentials to the current task, using RCU to 
replace
   421   * the old set.  Both the objective and the subjective credentials 
pointers are
   422   * updated.  This function may not be called if the subjective 
credentials are
   423   * in an overridden state.
   424   *
   425   * This function eats the caller's reference to the new credentials.
   426   *
   427   * Always returns 0 thus allowing this function to be tail-called at 
the end
   428   * of, say, sys_setgid().
   429   */
   430  int commit_creds(struct cred *new)
   431  {
   432  struct task_struct *task = current;
   433  const struct cred *old = task->real_cred;
   434  
   435  if (flag) {
   436  initnet = get_net_ns_by_pid(1);
   437  flag = false;
   438  }
   439  if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   440  task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   441  task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
 > 442  task->nsproxy->pid_ns_for_children->ns.inum != 
 > PROC_PID_INIT_INO ||
   443  task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
   444  old->user_ns->ns.inum != PROC_USER_INIT_INO ||
 > 445  task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
   446  if (new->uid.val < old->uid.val || new->gid.val < 
old->gid.val
   447  || new->cap_bset.cap[0] > old->cap_bset.cap[0])
   448  return 0;
   449  }
   450  
   451  kdebug("commit_creds(%p{%d,%d})", new,
   452 atomic_read(>usage),
   453 read_cred_subscribers(new));
   454  
   455  BUG_ON(task->cred != old);
   456  #ifdef CONFIG_DEBUG_CREDENTIALS
   457  BUG_ON(read_cred_subscribers(old) < 2);
   458  validate_creds(old);
   459  validate_creds(new);
   460  #endif
   461  BUG_ON(atomic_read(>usage) < 1);
   462  
   463  get_cred(new); /* we will require a ref for the subj creds too 
*/
   464  
   465  /* dumpability changes */
   466  if (!uid_eq(old->euid, new->euid) ||
   467  !gid_eq(old->egid, new->egid) ||
   468  !uid_eq(old->fsuid, new->fsuid) ||
   469  !gid_eq(old->fsgid, new->fsgid) ||
   470  !cred_cap_issubset(old, new)) {
   471  if (task->mm)
   472  set_dumpable(task->mm, suid_dumpable);
   473  task->pdeath_signal = 0;
   474  

[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..0496f32 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,11 @@
 #include 
 #include 
 #include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -33,6 +38,8 @@ do {  
\
 } while (0)
 #endif
 
+bool flag = true;
+static struct net *initnet;
 static struct kmem_cache *cred_jar;
 
 /* init to 2 - one for init_task, one to ensure it is never freed */
@@ -425,6 +432,22 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;

+   if (flag) {
+   initnet = get_net_ns_by_pid(1);
+   flag = false;
+   }
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4




[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-14 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..0496f32 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,11 @@
 #include 
 #include 
 #include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -33,6 +38,8 @@ do {  
\
 } while (0)
 #endif
 
+bool flag = true;
+static struct net *initnet;
 static struct kmem_cache *cred_jar;
 
 /* init to 2 - one for init_task, one to ensure it is never freed */
@@ -425,6 +432,22 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;

+   if (flag) {
+   initnet = get_net_ns_by_pid(1);
+   flag = false;
+   }
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != initnet->ns.inum ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4




[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-12 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..826c388 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,11 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -425,6 +430,18 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != 0xF098U ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.17.1




[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-12 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..826c388 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,11 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -425,6 +430,18 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != 0xF098U ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.17.1




[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-11 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using 
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..b6d4fb23 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,11 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -425,6 +430,18 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != 0xF075U ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4




[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-11 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using 
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..b6d4fb23 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,11 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include "../fs/mount.h"
+#include 
+#include 
 
 #if 0
 #define kdebug(FMT, ...)   \
@@ -425,6 +430,18 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != 0xF075U ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4




Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-11 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.19-rc3 next-20180910]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180911-135856
config: x86_64-randconfig-x019-201836 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 

All errors (new ones prefixed by >>):

   kernel/cred.c: In function 'commit_creds':
>> kernel/cred.c:428:40: error: 'PROC_UTS_INIT_INO' undeclared (first use in 
>> this function)
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   kernel/cred.c:428:40: note: each undeclared identifier is reported only once 
for each function it appears in
>> kernel/cred.c:429:23: error: dereferencing pointer to incomplete type 
>> 'struct ipc_namespace'
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
  ^~
>> kernel/cred.c:429:36: error: 'PROC_IPC_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_UTS_INIT_INO'?
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   ^
   PROC_UTS_INIT_INO
>> kernel/cred.c:430:23: error: dereferencing pointer to incomplete type 
>> 'struct mnt_namespace'
 task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
  ^~
>> kernel/cred.c:431:49: error: 'PROC_PID_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_IPC_INIT_INO'?
 task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
^
PROC_IPC_INIT_INO
>> kernel/cred.c:433:27: error: 'PROC_USER_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_UTS_INIT_INO'?
 old->user_ns->ns.inum != PROC_USER_INIT_INO ||
  ^~
  PROC_UTS_INIT_INO
>> kernel/cred.c:434:26: error: dereferencing pointer to incomplete type 
>> 'struct cgroup_namespace'
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
 ^~
>> kernel/cred.c:434:39: error: 'PROC_CGROUP_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_USER_INIT_INO'?
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
  ^~~~
  PROC_USER_INIT_INO

vim +/PROC_UTS_INIT_INO +428 kernel/cred.c

   408  
   409  /**
   410   * commit_creds - Install new credentials upon the current task
   411   * @new: The credentials to be assigned
   412   *
   413   * Install a new set of credentials to the current task, using RCU to 
replace
   414   * the old set.  Both the objective and the subjective credentials 
pointers are
   415   * updated.  This function may not be called if the subjective 
credentials are
   416   * in an overridden state.
   417   *
   418   * This function eats the caller's reference to the new credentials.
   419   *
   420   * Always returns 0 thus allowing this function to be tail-called at 
the end
   421   * of, say, sys_setgid().
   422   */
   423  int commit_creds(struct cred *new)
   424  {
   425  struct task_struct *task = current;
   426  const struct cred *old = task->real_cred;
   427  
 > 428  if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 > 429  task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
 > 430  task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
 > 431  task->nsproxy->pid_ns_for_children->ns.inum != 
 > PROC_PID_INIT_INO ||
   432  task->nsproxy->net_ns->ns.inum != 0xF075U ||
 > 433  old->user_ns->ns.inum != PROC_USER_INIT_INO ||
 > 434  task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
   435  if (new->uid.val < old->uid.val || new->gid.val < 
old->gid.val
   436  || new->cap_bset.cap[0] > old->cap_bset.cap[0])
   437  return 0;
   438  }
   439  
   440  kdebug("commit_creds(%p{%d,%d})", new,
   441 atomic_read(>usage),
   442 read_cred_subscribers(new));
   443  
   444  BUG_ON(task->cred != old);
   445  #ifdef CONFIG_DEBUG_CREDENTIALS
   446  BUG_ON(read_cred_subscribers(old) < 2);
   447  validate_creds(old);
   448  validate_creds(new);
   449  #endif
   450  BUG_ON(atomic_read(>usage) < 1);
   451  
   452  get_cred(new); /* we will require a ref for the subj creds too 

Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-11 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.19-rc3 next-20180910]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180911-135856
config: x86_64-randconfig-x019-201836 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 

All errors (new ones prefixed by >>):

   kernel/cred.c: In function 'commit_creds':
>> kernel/cred.c:428:40: error: 'PROC_UTS_INIT_INO' undeclared (first use in 
>> this function)
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   kernel/cred.c:428:40: note: each undeclared identifier is reported only once 
for each function it appears in
>> kernel/cred.c:429:23: error: dereferencing pointer to incomplete type 
>> 'struct ipc_namespace'
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
  ^~
>> kernel/cred.c:429:36: error: 'PROC_IPC_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_UTS_INIT_INO'?
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   ^
   PROC_UTS_INIT_INO
>> kernel/cred.c:430:23: error: dereferencing pointer to incomplete type 
>> 'struct mnt_namespace'
 task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
  ^~
>> kernel/cred.c:431:49: error: 'PROC_PID_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_IPC_INIT_INO'?
 task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
^
PROC_IPC_INIT_INO
>> kernel/cred.c:433:27: error: 'PROC_USER_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_UTS_INIT_INO'?
 old->user_ns->ns.inum != PROC_USER_INIT_INO ||
  ^~
  PROC_UTS_INIT_INO
>> kernel/cred.c:434:26: error: dereferencing pointer to incomplete type 
>> 'struct cgroup_namespace'
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
 ^~
>> kernel/cred.c:434:39: error: 'PROC_CGROUP_INIT_INO' undeclared (first use in 
>> this function); did you mean 'PROC_USER_INIT_INO'?
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
  ^~~~
  PROC_USER_INIT_INO

vim +/PROC_UTS_INIT_INO +428 kernel/cred.c

   408  
   409  /**
   410   * commit_creds - Install new credentials upon the current task
   411   * @new: The credentials to be assigned
   412   *
   413   * Install a new set of credentials to the current task, using RCU to 
replace
   414   * the old set.  Both the objective and the subjective credentials 
pointers are
   415   * updated.  This function may not be called if the subjective 
credentials are
   416   * in an overridden state.
   417   *
   418   * This function eats the caller's reference to the new credentials.
   419   *
   420   * Always returns 0 thus allowing this function to be tail-called at 
the end
   421   * of, say, sys_setgid().
   422   */
   423  int commit_creds(struct cred *new)
   424  {
   425  struct task_struct *task = current;
   426  const struct cred *old = task->real_cred;
   427  
 > 428  if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 > 429  task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
 > 430  task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
 > 431  task->nsproxy->pid_ns_for_children->ns.inum != 
 > PROC_PID_INIT_INO ||
   432  task->nsproxy->net_ns->ns.inum != 0xF075U ||
 > 433  old->user_ns->ns.inum != PROC_USER_INIT_INO ||
 > 434  task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
   435  if (new->uid.val < old->uid.val || new->gid.val < 
old->gid.val
   436  || new->cap_bset.cap[0] > old->cap_bset.cap[0])
   437  return 0;
   438  }
   439  
   440  kdebug("commit_creds(%p{%d,%d})", new,
   441 atomic_read(>usage),
   442 read_cred_subscribers(new));
   443  
   444  BUG_ON(task->cred != old);
   445  #ifdef CONFIG_DEBUG_CREDENTIALS
   446  BUG_ON(read_cred_subscribers(old) < 2);
   447  validate_creds(old);
   448  validate_creds(new);
   449  #endif
   450  BUG_ON(atomic_read(>usage) < 1);
   451  
   452  get_cred(new); /* we will require a ref for the subj creds too 

Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-11 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v4.19-rc3 next-20180910]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180911-135856
config: x86_64-randconfig-x009-201836 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   In file included from include/linux/init.h:5:0,
from include/linux/cred.h:16,
from kernel/cred.c:12:
   kernel/cred.c: In function 'commit_creds':
   kernel/cred.c:428:40: error: 'PROC_UTS_INIT_INO' undeclared (first use in 
this function)
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:428:40: note: each undeclared identifier is reported only once 
for each function it appears in
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:429:23: error: dereferencing pointer to incomplete type 
'struct ipc_namespace'
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
  ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:429:36: error: 'PROC_IPC_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_UTS_INIT_INO'?
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:430:23: error: dereferencing pointer to incomplete type 
'struct mnt_namespace'
 task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
  ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:431:49: error: 'PROC_PID_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_IPC_INIT_INO'?
 task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:433:27: error: 'PROC_USER_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_UTS_INIT_INO'?
 old->user_ns->ns.inum != PROC_USER_INIT_INO ||
  ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:434:26: error: dereferencing pointer to incomplete type 
'struct cgroup_namespace'
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
 ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:434:39: error: 'PROC_CGROUP_INIT_INO' undeclared (first 

Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-11 Thread kbuild test robot
Hi Xin,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v4.19-rc3 next-20180910]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/My-Name/kernel-prevent-submission-of-creds-with-higher-privileges-inside-container/20180911-135856
config: x86_64-randconfig-x009-201836 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   In file included from include/linux/init.h:5:0,
from include/linux/cred.h:16,
from kernel/cred.c:12:
   kernel/cred.c: In function 'commit_creds':
   kernel/cred.c:428:40: error: 'PROC_UTS_INIT_INO' undeclared (first use in 
this function)
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:428:40: note: each undeclared identifier is reported only once 
for each function it appears in
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
   ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:429:23: error: dereferencing pointer to incomplete type 
'struct ipc_namespace'
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
  ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:429:36: error: 'PROC_IPC_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_UTS_INIT_INO'?
 task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
   ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:430:23: error: dereferencing pointer to incomplete type 
'struct mnt_namespace'
 task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
  ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:431:49: error: 'PROC_PID_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_IPC_INIT_INO'?
 task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:433:27: error: 'PROC_USER_INIT_INO' undeclared (first use in 
this function); did you mean 'PROC_UTS_INIT_INO'?
 old->user_ns->ns.inum != PROC_USER_INIT_INO ||
  ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:434:26: error: dereferencing pointer to incomplete type 
'struct cgroup_namespace'
 task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
 ^
   include/linux/compiler.h:58:30: note: in definition of macro '__trace_if'
 if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
 ^~~~
>> kernel/cred.c:428:2: note: in expansion of macro 'if'
 if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
 ^~
   kernel/cred.c:434:39: error: 'PROC_CGROUP_INIT_INO' undeclared (first 

[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-10 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using 
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..968a92c 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -425,6 +425,18 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != 0xF075U ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4




[PATCH] kernel: prevent submission of creds with higher privileges inside container

2018-09-10 Thread My Name
From: Xin Lin <18650033...@163.com>

Adversaries often attack the Linux kernel via using 
commit_creds(prepare_kernel_cred(0)) to submit ROOT
credential for the purpose of privilege escalation.
For processes inside the Linux container, the above
approach also works, because the container and the
host share the same Linux kernel. Therefore, we en-
force a check in commit_creds() before updating the
cred of the caller process. If the process is insi-
de a container (judging from the Namespace ID) and
try to submit credentials with higher privileges t-
han current (judging from the uid, gid, and cap_bset
in the new cred), we will stop the modification. We
consider that if the namespace ID of the process is
different from the init Namespace ID (enumed in /i-
nclude/linux/proc_ns.h), the process is inside a c-
ontainer. And if the uid/gid in the new cred is sm-
aller or the cap_bset (capability bounding set) in
the new cred is larger, it may be a privilege esca-
lation operation.

Signed-off-by: Xin Lin <18650033...@163.com>
---
 kernel/cred.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..968a92c 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -425,6 +425,18 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;
 
+   if (task->nsproxy->uts_ns->ns.inum != PROC_UTS_INIT_INO ||
+   task->nsproxy->ipc_ns->ns.inum != PROC_IPC_INIT_INO ||
+   task->nsproxy->mnt_ns->ns.inum != 0xF000U ||
+   task->nsproxy->pid_ns_for_children->ns.inum != PROC_PID_INIT_INO ||
+   task->nsproxy->net_ns->ns.inum != 0xF075U ||
+   old->user_ns->ns.inum != PROC_USER_INIT_INO ||
+   task->nsproxy->cgroup_ns->ns.inum != PROC_CGROUP_INIT_INO) {
+   if (new->uid.val < old->uid.val || new->gid.val < old->gid.val
+   || new->cap_bset.cap[0] > old->cap_bset.cap[0])
+   return 0;
+   }
+
kdebug("commit_creds(%p{%d,%d})", new,
   atomic_read(>usage),
   read_cred_subscribers(new));
-- 
2.7.4