diff options
| -rw-r--r-- | MAINTAINERS | 1 | ||||
| -rw-r--r-- | include/trace/events/capability.h | 57 | ||||
| -rw-r--r-- | security/commoncap.c | 61 | 
3 files changed, 99 insertions, 20 deletions
| diff --git a/MAINTAINERS b/MAINTAINERS index aeb5f3cc58a1..8e047e20fbd8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5182,6 +5182,7 @@ M:	Serge Hallyn <serge@hallyn.com>  L:	linux-security-module@vger.kernel.org  S:	Supported  F:	include/linux/capability.h +F:	include/trace/events/capability.h  F:	include/uapi/linux/capability.h  F:	kernel/capability.c  F:	security/commoncap.c diff --git a/include/trace/events/capability.h b/include/trace/events/capability.h new file mode 100644 index 000000000000..17340257946c --- /dev/null +++ b/include/trace/events/capability.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM capability + +#if !defined(_TRACE_CAPABILITY_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_CAPABILITY_H + +#include <linux/cred.h> +#include <linux/tracepoint.h> +#include <linux/user_namespace.h> + +/** + * cap_capable - called after it's determined if a task has a particular + * effective capability + * + * @cred: The credentials used + * @target_ns: The user namespace of the resource being accessed + * @capable_ns: The user namespace in which the credential provides the + *              capability to access the targeted resource. + *              This will be NULL if ret is not 0. + * @cap: The capability to check for + * @ret: The return value of the check: 0 if it does, -ve if it does not + * + * Allows to trace calls to cap_capable in commoncap.c + */ +TRACE_EVENT(cap_capable, + +	TP_PROTO(const struct cred *cred, struct user_namespace *target_ns, +		const struct user_namespace *capable_ns, int cap, int ret), + +	TP_ARGS(cred, target_ns, capable_ns, cap, ret), + +	TP_STRUCT__entry( +		__field(const struct cred *, cred) +		__field(struct user_namespace *, target_ns) +		__field(const struct user_namespace *, capable_ns) +		__field(int, cap) +		__field(int, ret) +	), + +	TP_fast_assign( +		__entry->cred       = cred; +		__entry->target_ns    = target_ns; +		__entry->capable_ns = ret == 0 ? capable_ns : NULL; +		__entry->cap        = cap; +		__entry->ret        = ret; +	), + +	TP_printk("cred %p, target_ns %p, capable_ns %p, cap %d, ret %d", +		__entry->cred, __entry->target_ns, __entry->capable_ns, __entry->cap, +		__entry->ret) +); + +#endif /* _TRACE_CAPABILITY_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/security/commoncap.c b/security/commoncap.c index 52ea01acb453..58a0c1c3e409 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -27,6 +27,9 @@  #include <linux/mnt_idmapping.h>  #include <uapi/linux/lsm.h> +#define CREATE_TRACE_POINTS +#include <trace/events/capability.h> +  /*   * If a non-root user executes a setuid-root binary in   * !secure(SECURE_NOROOT) mode, then we raise capabilities. @@ -50,24 +53,24 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)  }  /** - * cap_capable - Determine whether a task has a particular effective capability + * cap_capable_helper - Determine whether a task has a particular effective + * capability.   * @cred: The credentials to use - * @targ_ns:  The user namespace in which we need the capability + * @target_ns:  The user namespace of the resource being accessed + * @cred_ns:  The user namespace of the credentials   * @cap: The capability to check for - * @opts: Bitmask of options defined in include/linux/security.h   *   * Determine whether the nominated task has the specified capability amongst   * its effective set, returning 0 if it does, -ve if it does not.   * - * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable() - * and has_capability() functions.  That is, it has the reverse semantics: - * cap_has_capability() returns 0 when a task has a capability, but the - * kernel's capable() and has_capability() returns 1 for this case. + * See cap_capable for more details.   */ -int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, -		int cap, unsigned int opts) +static inline int cap_capable_helper(const struct cred *cred, +				     struct user_namespace *target_ns, +				     const struct user_namespace *cred_ns, +				     int cap)  { -	struct user_namespace *ns = targ_ns; +	struct user_namespace *ns = target_ns;  	/* See if cred has the capability in the target user namespace  	 * by examining the target user namespace and all of the target @@ -75,21 +78,21 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,  	 */  	for (;;) {  		/* Do we have the necessary capabilities? */ -		if (ns == cred->user_ns) +		if (likely(ns == cred_ns))  			return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;  		/*  		 * If we're already at a lower level than we're looking for,  		 * we're done searching.  		 */ -		if (ns->level <= cred->user_ns->level) +		if (ns->level <= cred_ns->level)  			return -EPERM;  		/*   		 * The owner of the user namespace in the parent of the  		 * user namespace has all caps.  		 */ -		if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid)) +		if ((ns->parent == cred_ns) && uid_eq(ns->owner, cred->euid))  			return 0;  		/* @@ -103,6 +106,31 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,  }  /** + * cap_capable - Determine whether a task has a particular effective capability + * @cred: The credentials to use + * @target_ns:  The user namespace of the resource being accessed + * @cap: The capability to check for + * @opts: Bitmask of options defined in include/linux/security.h (unused) + * + * Determine whether the nominated task has the specified capability amongst + * its effective set, returning 0 if it does, -ve if it does not. + * + * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable() + * and has_capability() functions.  That is, it has the reverse semantics: + * cap_has_capability() returns 0 when a task has a capability, but the + * kernel's capable() and has_capability() returns 1 for this case. + */ +int cap_capable(const struct cred *cred, struct user_namespace *target_ns, +		int cap, unsigned int opts) +{ +	const struct user_namespace *cred_ns = cred->user_ns; +	int ret = cap_capable_helper(cred, target_ns, cred_ns, cap); + +	trace_cap_capable(cred, target_ns, cred_ns, cap, ret); +	return ret; +} + +/**   * cap_settime - Determine whether the current process may set the system clock   * @ts: The time to set   * @tz: The timezone to set @@ -1445,12 +1473,6 @@ int cap_mmap_addr(unsigned long addr)  	return ret;  } -int cap_mmap_file(struct file *file, unsigned long reqprot, -		  unsigned long prot, unsigned long flags) -{ -	return 0; -} -  #ifdef CONFIG_SECURITY  static const struct lsm_id capability_lsmid = { @@ -1470,7 +1492,6 @@ static struct security_hook_list capability_hooks[] __ro_after_init = {  	LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv),  	LSM_HOOK_INIT(inode_getsecurity, cap_inode_getsecurity),  	LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), -	LSM_HOOK_INIT(mmap_file, cap_mmap_file),  	LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid),  	LSM_HOOK_INIT(task_prctl, cap_task_prctl),  	LSM_HOOK_INIT(task_setscheduler, cap_task_setscheduler), | 
