Re: [PATCH] kernel: prevent submission of creds with higher privileges inside container
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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