Message ID | 20190115180421.102209-1-mortonm@chromium.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v3,1/2] LSM: mark all set*uid call sites in kernel/sys.c | expand |
On Tue, Jan 15, 2019 at 10:04 AM <mortonm@chromium.org> wrote: > > From: Micah Morton <mortonm@chromium.org> > > This change ensures that the set*uid family of syscalls in kernel/sys.c > (setreuid, setuid, setresuid, setfsuid) all call ns_capable_common with > the CAP_OPT_INSETID flag, so capability checks in the security_capable > hook can know whether they are being called from within a set*uid > syscall. This change is a no-op by itself, but is needed for the > proposed SafeSetID LSM. > > Signed-off-by: Micah Morton <mortonm@chromium.org> Reviewed-by: Kees Cook <keescook@chromium.org> -Kees > --- > These changes used to be part of the main SafeSetID LSM patch set. > > include/linux/capability.h | 5 +++++ > kernel/capability.c | 19 +++++++++++++++++++ > kernel/sys.c | 10 +++++----- > 3 files changed, 29 insertions(+), 5 deletions(-) > > diff --git a/include/linux/capability.h b/include/linux/capability.h > index f640dcbc880c..c3f9a4d558a0 100644 > --- a/include/linux/capability.h > +++ b/include/linux/capability.h > @@ -209,6 +209,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, > extern bool capable(int cap); > extern bool ns_capable(struct user_namespace *ns, int cap); > extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); > +extern bool ns_capable_setid(struct user_namespace *ns, int cap); > #else > static inline bool has_capability(struct task_struct *t, int cap) > { > @@ -240,6 +241,10 @@ static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) > { > return true; > } > +static inline bool ns_capable_setid(struct user_namespace *ns, int cap) > +{ > + return true; > +} > #endif /* CONFIG_MULTIUSER */ > extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode); > extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); > diff --git a/kernel/capability.c b/kernel/capability.c > index 7718d7dcadc7..e0734ace5bc2 100644 > --- a/kernel/capability.c > +++ b/kernel/capability.c > @@ -417,6 +417,25 @@ bool ns_capable_noaudit(struct user_namespace *ns, int cap) > } > EXPORT_SYMBOL(ns_capable_noaudit); > > +/** > + * ns_capable_setid - Determine if the current task has a superior capability > + * in effect, while signalling that this check is being done from within a > + * setid syscall. > + * @ns: The usernamespace we want the capability in > + * @cap: The capability to be tested for > + * > + * Return true if the current task has the given superior capability currently > + * available for use, false if not. > + * > + * This sets PF_SUPERPRIV on the task if the capability is available on the > + * assumption that it's about to be used. > + */ > +bool ns_capable_setid(struct user_namespace *ns, int cap) > +{ > + return ns_capable_common(ns, cap, CAP_OPT_INSETID); > +} > +EXPORT_SYMBOL(ns_capable_setid); > + > /** > * capable - Determine if the current task has a superior capability in effect > * @cap: The capability to be tested for > diff --git a/kernel/sys.c b/kernel/sys.c > index a48cbf1414b8..a98061c1a124 100644 > --- a/kernel/sys.c > +++ b/kernel/sys.c > @@ -516,7 +516,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid) > new->uid = kruid; > if (!uid_eq(old->uid, kruid) && > !uid_eq(old->euid, kruid) && > - !ns_capable(old->user_ns, CAP_SETUID)) > + !ns_capable_setid(old->user_ns, CAP_SETUID)) > goto error; > } > > @@ -525,7 +525,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid) > if (!uid_eq(old->uid, keuid) && > !uid_eq(old->euid, keuid) && > !uid_eq(old->suid, keuid) && > - !ns_capable(old->user_ns, CAP_SETUID)) > + !ns_capable_setid(old->user_ns, CAP_SETUID)) > goto error; > } > > @@ -584,7 +584,7 @@ long __sys_setuid(uid_t uid) > old = current_cred(); > > retval = -EPERM; > - if (ns_capable(old->user_ns, CAP_SETUID)) { > + if (ns_capable_setid(old->user_ns, CAP_SETUID)) { > new->suid = new->uid = kuid; > if (!uid_eq(kuid, old->uid)) { > retval = set_user(new); > @@ -646,7 +646,7 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) > old = current_cred(); > > retval = -EPERM; > - if (!ns_capable(old->user_ns, CAP_SETUID)) { > + if (!ns_capable_setid(old->user_ns, CAP_SETUID)) { > if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && > !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) > goto error; > @@ -814,7 +814,7 @@ long __sys_setfsuid(uid_t uid) > > if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || > uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || > - ns_capable(old->user_ns, CAP_SETUID)) { > + ns_capable_setid(old->user_ns, CAP_SETUID)) { > if (!uid_eq(kuid, old->fsuid)) { > new->fsuid = kuid; > if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) > -- > 2.20.1.97.g81188d93c3-goog >
diff --git a/include/linux/capability.h b/include/linux/capability.h index f640dcbc880c..c3f9a4d558a0 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -209,6 +209,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); +extern bool ns_capable_setid(struct user_namespace *ns, int cap); #else static inline bool has_capability(struct task_struct *t, int cap) { @@ -240,6 +241,10 @@ static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) { return true; } +static inline bool ns_capable_setid(struct user_namespace *ns, int cap) +{ + return true; +} #endif /* CONFIG_MULTIUSER */ extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode); extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); diff --git a/kernel/capability.c b/kernel/capability.c index 7718d7dcadc7..e0734ace5bc2 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -417,6 +417,25 @@ bool ns_capable_noaudit(struct user_namespace *ns, int cap) } EXPORT_SYMBOL(ns_capable_noaudit); +/** + * ns_capable_setid - Determine if the current task has a superior capability + * in effect, while signalling that this check is being done from within a + * setid syscall. + * @ns: The usernamespace we want the capability in + * @cap: The capability to be tested for + * + * Return true if the current task has the given superior capability currently + * available for use, false if not. + * + * This sets PF_SUPERPRIV on the task if the capability is available on the + * assumption that it's about to be used. + */ +bool ns_capable_setid(struct user_namespace *ns, int cap) +{ + return ns_capable_common(ns, cap, CAP_OPT_INSETID); +} +EXPORT_SYMBOL(ns_capable_setid); + /** * capable - Determine if the current task has a superior capability in effect * @cap: The capability to be tested for diff --git a/kernel/sys.c b/kernel/sys.c index a48cbf1414b8..a98061c1a124 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -516,7 +516,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid) new->uid = kruid; if (!uid_eq(old->uid, kruid) && !uid_eq(old->euid, kruid) && - !ns_capable(old->user_ns, CAP_SETUID)) + !ns_capable_setid(old->user_ns, CAP_SETUID)) goto error; } @@ -525,7 +525,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid) if (!uid_eq(old->uid, keuid) && !uid_eq(old->euid, keuid) && !uid_eq(old->suid, keuid) && - !ns_capable(old->user_ns, CAP_SETUID)) + !ns_capable_setid(old->user_ns, CAP_SETUID)) goto error; } @@ -584,7 +584,7 @@ long __sys_setuid(uid_t uid) old = current_cred(); retval = -EPERM; - if (ns_capable(old->user_ns, CAP_SETUID)) { + if (ns_capable_setid(old->user_ns, CAP_SETUID)) { new->suid = new->uid = kuid; if (!uid_eq(kuid, old->uid)) { retval = set_user(new); @@ -646,7 +646,7 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) old = current_cred(); retval = -EPERM; - if (!ns_capable(old->user_ns, CAP_SETUID)) { + if (!ns_capable_setid(old->user_ns, CAP_SETUID)) { if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) goto error; @@ -814,7 +814,7 @@ long __sys_setfsuid(uid_t uid) if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || - ns_capable(old->user_ns, CAP_SETUID)) { + ns_capable_setid(old->user_ns, CAP_SETUID)) { if (!uid_eq(kuid, old->fsuid)) { new->fsuid = kuid; if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)