LSM: generalize flag passing to security_capable
[ Upstream commit c1a85a00ea66cb6f0bd0f14e47c28c2b0999799f ] This patch provides a general mechanism for passing flags to the security_capable LSM hook. It replaces the specific 'audit' flag that is used to tell security_capable whether it should log an audit message for the given capability check. The reason for generalizing this flag passing is so we can add an additional flag that signifies whether security_capable is being called by a setid syscall (which is needed by the proposed SafeSetID LSM). Signed-off-by: Micah Morton <mortonm@chromium.org> Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: James Morris <james.morris@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
991d8c73d5
commit
87ca9aaf0c
13 changed files with 71 additions and 67 deletions
|
@ -1270,7 +1270,7 @@
|
||||||
* @cred contains the credentials to use.
|
* @cred contains the credentials to use.
|
||||||
* @ns contains the user namespace we want the capability in
|
* @ns contains the user namespace we want the capability in
|
||||||
* @cap contains the capability <include/linux/capability.h>.
|
* @cap contains the capability <include/linux/capability.h>.
|
||||||
* @audit contains whether to write an audit message or not
|
* @opts contains options for the capable check <include/linux/security.h>
|
||||||
* Return 0 if the capability is granted for @tsk.
|
* Return 0 if the capability is granted for @tsk.
|
||||||
* @syslog:
|
* @syslog:
|
||||||
* Check permission before accessing the kernel message ring or changing
|
* Check permission before accessing the kernel message ring or changing
|
||||||
|
@ -1446,8 +1446,10 @@ union security_list_options {
|
||||||
const kernel_cap_t *effective,
|
const kernel_cap_t *effective,
|
||||||
const kernel_cap_t *inheritable,
|
const kernel_cap_t *inheritable,
|
||||||
const kernel_cap_t *permitted);
|
const kernel_cap_t *permitted);
|
||||||
int (*capable)(const struct cred *cred, struct user_namespace *ns,
|
int (*capable)(const struct cred *cred,
|
||||||
int cap, int audit);
|
struct user_namespace *ns,
|
||||||
|
int cap,
|
||||||
|
unsigned int opts);
|
||||||
int (*quotactl)(int cmds, int type, int id, struct super_block *sb);
|
int (*quotactl)(int cmds, int type, int id, struct super_block *sb);
|
||||||
int (*quota_on)(struct dentry *dentry);
|
int (*quota_on)(struct dentry *dentry);
|
||||||
int (*syslog)(int type);
|
int (*syslog)(int type);
|
||||||
|
|
|
@ -54,9 +54,12 @@ struct xattr;
|
||||||
struct xfrm_sec_ctx;
|
struct xfrm_sec_ctx;
|
||||||
struct mm_struct;
|
struct mm_struct;
|
||||||
|
|
||||||
|
/* Default (no) options for the capable function */
|
||||||
|
#define CAP_OPT_NONE 0x0
|
||||||
/* If capable should audit the security request */
|
/* If capable should audit the security request */
|
||||||
#define SECURITY_CAP_NOAUDIT 0
|
#define CAP_OPT_NOAUDIT BIT(1)
|
||||||
#define SECURITY_CAP_AUDIT 1
|
/* If capable is being called by a setid function */
|
||||||
|
#define CAP_OPT_INSETID BIT(2)
|
||||||
|
|
||||||
/* LSM Agnostic defines for sb_set_mnt_opts */
|
/* LSM Agnostic defines for sb_set_mnt_opts */
|
||||||
#define SECURITY_LSM_NATIVE_LABELS 1
|
#define SECURITY_LSM_NATIVE_LABELS 1
|
||||||
|
@ -72,7 +75,7 @@ enum lsm_event {
|
||||||
|
|
||||||
/* These functions are in security/commoncap.c */
|
/* These functions are in security/commoncap.c */
|
||||||
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
|
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
|
||||||
int cap, int audit);
|
int cap, unsigned int opts);
|
||||||
extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz);
|
extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz);
|
||||||
extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
|
extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
|
||||||
extern int cap_ptrace_traceme(struct task_struct *parent);
|
extern int cap_ptrace_traceme(struct task_struct *parent);
|
||||||
|
@ -233,10 +236,10 @@ int security_capset(struct cred *new, const struct cred *old,
|
||||||
const kernel_cap_t *effective,
|
const kernel_cap_t *effective,
|
||||||
const kernel_cap_t *inheritable,
|
const kernel_cap_t *inheritable,
|
||||||
const kernel_cap_t *permitted);
|
const kernel_cap_t *permitted);
|
||||||
int security_capable(const struct cred *cred, struct user_namespace *ns,
|
int security_capable(const struct cred *cred,
|
||||||
int cap);
|
struct user_namespace *ns,
|
||||||
int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
|
int cap,
|
||||||
int cap);
|
unsigned int opts);
|
||||||
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
|
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
|
||||||
int security_quota_on(struct dentry *dentry);
|
int security_quota_on(struct dentry *dentry);
|
||||||
int security_syslog(int type);
|
int security_syslog(int type);
|
||||||
|
@ -492,14 +495,11 @@ static inline int security_capset(struct cred *new,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int security_capable(const struct cred *cred,
|
static inline int security_capable(const struct cred *cred,
|
||||||
struct user_namespace *ns, int cap)
|
struct user_namespace *ns,
|
||||||
|
int cap,
|
||||||
|
unsigned int opts)
|
||||||
{
|
{
|
||||||
return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT);
|
return cap_capable(cred, ns, cap, opts);
|
||||||
}
|
|
||||||
|
|
||||||
static inline int security_capable_noaudit(const struct cred *cred,
|
|
||||||
struct user_namespace *ns, int cap) {
|
|
||||||
return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int security_quotactl(int cmds, int type, int id,
|
static inline int security_quotactl(int cmds, int type, int id,
|
||||||
|
|
|
@ -299,7 +299,7 @@ bool has_ns_capability(struct task_struct *t,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
ret = security_capable(__task_cred(t), ns, cap);
|
ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NONE);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
|
@ -340,7 +340,7 @@ bool has_ns_capability_noaudit(struct task_struct *t,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
ret = security_capable_noaudit(__task_cred(t), ns, cap);
|
ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NOAUDIT);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
|
@ -363,7 +363,9 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
|
||||||
return has_ns_capability_noaudit(t, &init_user_ns, cap);
|
return has_ns_capability_noaudit(t, &init_user_ns, cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
|
static bool ns_capable_common(struct user_namespace *ns,
|
||||||
|
int cap,
|
||||||
|
unsigned int opts)
|
||||||
{
|
{
|
||||||
int capable;
|
int capable;
|
||||||
|
|
||||||
|
@ -372,8 +374,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
capable = audit ? security_capable(current_cred(), ns, cap) :
|
capable = security_capable(current_cred(), ns, cap, opts);
|
||||||
security_capable_noaudit(current_cred(), ns, cap);
|
|
||||||
if (capable == 0) {
|
if (capable == 0) {
|
||||||
current->flags |= PF_SUPERPRIV;
|
current->flags |= PF_SUPERPRIV;
|
||||||
return true;
|
return true;
|
||||||
|
@ -394,7 +395,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
|
||||||
*/
|
*/
|
||||||
bool ns_capable(struct user_namespace *ns, int cap)
|
bool ns_capable(struct user_namespace *ns, int cap)
|
||||||
{
|
{
|
||||||
return ns_capable_common(ns, cap, true);
|
return ns_capable_common(ns, cap, CAP_OPT_NONE);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ns_capable);
|
EXPORT_SYMBOL(ns_capable);
|
||||||
|
|
||||||
|
@ -412,7 +413,7 @@ EXPORT_SYMBOL(ns_capable);
|
||||||
*/
|
*/
|
||||||
bool ns_capable_noaudit(struct user_namespace *ns, int cap)
|
bool ns_capable_noaudit(struct user_namespace *ns, int cap)
|
||||||
{
|
{
|
||||||
return ns_capable_common(ns, cap, false);
|
return ns_capable_common(ns, cap, CAP_OPT_NOAUDIT);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ns_capable_noaudit);
|
EXPORT_SYMBOL(ns_capable_noaudit);
|
||||||
|
|
||||||
|
@ -448,10 +449,11 @@ EXPORT_SYMBOL(capable);
|
||||||
bool file_ns_capable(const struct file *file, struct user_namespace *ns,
|
bool file_ns_capable(const struct file *file, struct user_namespace *ns,
|
||||||
int cap)
|
int cap)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!cap_valid(cap)))
|
if (WARN_ON_ONCE(!cap_valid(cap)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (security_capable(file->f_cred, ns, cap) == 0)
|
if (security_capable(file->f_cred, ns, cap, CAP_OPT_NONE) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -500,10 +502,12 @@ bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns)
|
||||||
{
|
{
|
||||||
int ret = 0; /* An absent tracer adds no restrictions */
|
int ret = 0; /* An absent tracer adds no restrictions */
|
||||||
const struct cred *cred;
|
const struct cred *cred;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
cred = rcu_dereference(tsk->ptracer_cred);
|
cred = rcu_dereference(tsk->ptracer_cred);
|
||||||
if (cred)
|
if (cred)
|
||||||
ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE);
|
ret = security_capable(cred, ns, CAP_SYS_PTRACE,
|
||||||
|
CAP_OPT_NOAUDIT);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -383,8 +383,8 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
|
||||||
* behavior of privileged children.
|
* behavior of privileged children.
|
||||||
*/
|
*/
|
||||||
if (!task_no_new_privs(current) &&
|
if (!task_no_new_privs(current) &&
|
||||||
security_capable_noaudit(current_cred(), current_user_ns(),
|
security_capable(current_cred(), current_user_ns(),
|
||||||
CAP_SYS_ADMIN) != 0)
|
CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0)
|
||||||
return ERR_PTR(-EACCES);
|
return ERR_PTR(-EACCES);
|
||||||
|
|
||||||
/* Allocate a new seccomp_filter */
|
/* Allocate a new seccomp_filter */
|
||||||
|
|
|
@ -110,13 +110,13 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
|
||||||
* profile_capable - test if profile allows use of capability @cap
|
* profile_capable - test if profile allows use of capability @cap
|
||||||
* @profile: profile being enforced (NOT NULL, NOT unconfined)
|
* @profile: profile being enforced (NOT NULL, NOT unconfined)
|
||||||
* @cap: capability to test if allowed
|
* @cap: capability to test if allowed
|
||||||
* @audit: whether an audit record should be generated
|
* @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
|
||||||
* @sa: audit data (MAY BE NULL indicating no auditing)
|
* @sa: audit data (MAY BE NULL indicating no auditing)
|
||||||
*
|
*
|
||||||
* Returns: 0 if allowed else -EPERM
|
* Returns: 0 if allowed else -EPERM
|
||||||
*/
|
*/
|
||||||
static int profile_capable(struct aa_profile *profile, int cap, int audit,
|
static int profile_capable(struct aa_profile *profile, int cap,
|
||||||
struct common_audit_data *sa)
|
unsigned int opts, struct common_audit_data *sa)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit,
|
||||||
else
|
else
|
||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
|
|
||||||
if (audit == SECURITY_CAP_NOAUDIT) {
|
if (opts & CAP_OPT_NOAUDIT) {
|
||||||
if (!COMPLAIN_MODE(profile))
|
if (!COMPLAIN_MODE(profile))
|
||||||
return error;
|
return error;
|
||||||
/* audit the cap request in complain mode but note that it
|
/* audit the cap request in complain mode but note that it
|
||||||
|
@ -142,13 +142,13 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit,
|
||||||
* aa_capable - test permission to use capability
|
* aa_capable - test permission to use capability
|
||||||
* @label: label being tested for capability (NOT NULL)
|
* @label: label being tested for capability (NOT NULL)
|
||||||
* @cap: capability to be tested
|
* @cap: capability to be tested
|
||||||
* @audit: whether an audit record should be generated
|
* @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
|
||||||
*
|
*
|
||||||
* Look up capability in profile capability set.
|
* Look up capability in profile capability set.
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, or else an error code.
|
* Returns: 0 on success, or else an error code.
|
||||||
*/
|
*/
|
||||||
int aa_capable(struct aa_label *label, int cap, int audit)
|
int aa_capable(struct aa_label *label, int cap, unsigned int opts)
|
||||||
{
|
{
|
||||||
struct aa_profile *profile;
|
struct aa_profile *profile;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
@ -156,7 +156,7 @@ int aa_capable(struct aa_label *label, int cap, int audit)
|
||||||
|
|
||||||
sa.u.cap = cap;
|
sa.u.cap = cap;
|
||||||
error = fn_for_each_confined(label, profile,
|
error = fn_for_each_confined(label, profile,
|
||||||
profile_capable(profile, cap, audit, &sa));
|
profile_capable(profile, cap, opts, &sa));
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct aa_caps {
|
||||||
|
|
||||||
extern struct aa_sfs_entry aa_sfs_entry_caps[];
|
extern struct aa_sfs_entry aa_sfs_entry_caps[];
|
||||||
|
|
||||||
int aa_capable(struct aa_label *label, int cap, int audit);
|
int aa_capable(struct aa_label *label, int cap, unsigned int opts);
|
||||||
|
|
||||||
static inline void aa_free_cap_rules(struct aa_caps *caps)
|
static inline void aa_free_cap_rules(struct aa_caps *caps)
|
||||||
{
|
{
|
||||||
|
|
|
@ -107,7 +107,8 @@ static int profile_tracer_perm(struct aa_profile *tracer,
|
||||||
aad(sa)->label = &tracer->label;
|
aad(sa)->label = &tracer->label;
|
||||||
aad(sa)->peer = tracee;
|
aad(sa)->peer = tracee;
|
||||||
aad(sa)->request = 0;
|
aad(sa)->request = 0;
|
||||||
aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1);
|
aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
|
||||||
|
CAP_OPT_NONE);
|
||||||
|
|
||||||
return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
|
return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,14 +174,14 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
|
static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
|
||||||
int cap, int audit)
|
int cap, unsigned int opts)
|
||||||
{
|
{
|
||||||
struct aa_label *label;
|
struct aa_label *label;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
label = aa_get_newest_cred_label(cred);
|
label = aa_get_newest_cred_label(cred);
|
||||||
if (!unconfined(label))
|
if (!unconfined(label))
|
||||||
error = aa_capable(label, cap, audit);
|
error = aa_capable(label, cap, opts);
|
||||||
aa_put_label(label);
|
aa_put_label(label);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (label != peer &&
|
if (label != peer &&
|
||||||
aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0)
|
aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
|
||||||
error = fn_for_each(label, profile,
|
error = fn_for_each(label, profile,
|
||||||
audit_resource(profile, resource,
|
audit_resource(profile, resource,
|
||||||
new_rlim->rlim_max, peer,
|
new_rlim->rlim_max, peer,
|
||||||
|
|
|
@ -69,7 +69,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
|
||||||
* kernel's capable() and has_capability() returns 1 for this case.
|
* kernel's capable() and has_capability() returns 1 for this case.
|
||||||
*/
|
*/
|
||||||
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||||
int cap, int audit)
|
int cap, unsigned int opts)
|
||||||
{
|
{
|
||||||
struct user_namespace *ns = targ_ns;
|
struct user_namespace *ns = targ_ns;
|
||||||
|
|
||||||
|
@ -223,12 +223,11 @@ int cap_capget(struct task_struct *target, kernel_cap_t *effective,
|
||||||
*/
|
*/
|
||||||
static inline int cap_inh_is_capped(void)
|
static inline int cap_inh_is_capped(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* they are so limited unless the current task has the CAP_SETPCAP
|
/* they are so limited unless the current task has the CAP_SETPCAP
|
||||||
* capability
|
* capability
|
||||||
*/
|
*/
|
||||||
if (cap_capable(current_cred(), current_cred()->user_ns,
|
if (cap_capable(current_cred(), current_cred()->user_ns,
|
||||||
CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
|
CAP_SETPCAP, CAP_OPT_NONE) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1212,8 +1211,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||||
|| ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|
|| ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|
||||||
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|
||||||
|| (cap_capable(current_cred(),
|
|| (cap_capable(current_cred(),
|
||||||
current_cred()->user_ns, CAP_SETPCAP,
|
current_cred()->user_ns,
|
||||||
SECURITY_CAP_AUDIT) != 0) /*[4]*/
|
CAP_SETPCAP,
|
||||||
|
CAP_OPT_NONE) != 0) /*[4]*/
|
||||||
/*
|
/*
|
||||||
* [1] no changing of bits that are locked
|
* [1] no changing of bits that are locked
|
||||||
* [2] no unlocking of locks
|
* [2] no unlocking of locks
|
||||||
|
@ -1308,9 +1308,10 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
|
||||||
{
|
{
|
||||||
int cap_sys_admin = 0;
|
int cap_sys_admin = 0;
|
||||||
|
|
||||||
if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
|
if (cap_capable(current_cred(), &init_user_ns,
|
||||||
SECURITY_CAP_NOAUDIT) == 0)
|
CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0)
|
||||||
cap_sys_admin = 1;
|
cap_sys_admin = 1;
|
||||||
|
|
||||||
return cap_sys_admin;
|
return cap_sys_admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1329,7 +1330,7 @@ int cap_mmap_addr(unsigned long addr)
|
||||||
|
|
||||||
if (addr < dac_mmap_min_addr) {
|
if (addr < dac_mmap_min_addr) {
|
||||||
ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
|
ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
|
||||||
SECURITY_CAP_AUDIT);
|
CAP_OPT_NONE);
|
||||||
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
|
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
current->flags |= PF_SUPERPRIV;
|
current->flags |= PF_SUPERPRIV;
|
||||||
|
|
|
@ -283,16 +283,12 @@ int security_capset(struct cred *new, const struct cred *old,
|
||||||
effective, inheritable, permitted);
|
effective, inheritable, permitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
int security_capable(const struct cred *cred, struct user_namespace *ns,
|
int security_capable(const struct cred *cred,
|
||||||
int cap)
|
struct user_namespace *ns,
|
||||||
|
int cap,
|
||||||
|
unsigned int opts)
|
||||||
{
|
{
|
||||||
return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT);
|
return call_int_hook(capable, 0, cred, ns, cap, opts);
|
||||||
}
|
|
||||||
|
|
||||||
int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
|
|
||||||
int cap)
|
|
||||||
{
|
|
||||||
return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
|
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
|
||||||
|
|
|
@ -1794,7 +1794,7 @@ static inline u32 signal_to_av(int sig)
|
||||||
|
|
||||||
/* Check whether a task is allowed to use a capability. */
|
/* Check whether a task is allowed to use a capability. */
|
||||||
static int cred_has_capability(const struct cred *cred,
|
static int cred_has_capability(const struct cred *cred,
|
||||||
int cap, int audit, bool initns)
|
int cap, unsigned int opts, bool initns)
|
||||||
{
|
{
|
||||||
struct common_audit_data ad;
|
struct common_audit_data ad;
|
||||||
struct av_decision avd;
|
struct av_decision avd;
|
||||||
|
@ -1821,7 +1821,7 @@ static int cred_has_capability(const struct cred *cred,
|
||||||
|
|
||||||
rc = avc_has_perm_noaudit(&selinux_state,
|
rc = avc_has_perm_noaudit(&selinux_state,
|
||||||
sid, sid, sclass, av, 0, &avd);
|
sid, sid, sclass, av, 0, &avd);
|
||||||
if (audit == SECURITY_CAP_AUDIT) {
|
if (!(opts & CAP_OPT_NOAUDIT)) {
|
||||||
int rc2 = avc_audit(&selinux_state,
|
int rc2 = avc_audit(&selinux_state,
|
||||||
sid, sid, sclass, av, &avd, rc, &ad, 0);
|
sid, sid, sclass, av, &avd, rc, &ad, 0);
|
||||||
if (rc2)
|
if (rc2)
|
||||||
|
@ -2341,9 +2341,9 @@ static int selinux_capset(struct cred *new, const struct cred *old,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
|
static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
|
||||||
int cap, int audit)
|
int cap, unsigned int opts)
|
||||||
{
|
{
|
||||||
return cred_has_capability(cred, cap, audit, ns == &init_user_ns);
|
return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
|
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
|
||||||
|
@ -2417,7 +2417,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
|
||||||
int rc, cap_sys_admin = 0;
|
int rc, cap_sys_admin = 0;
|
||||||
|
|
||||||
rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
|
rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
|
||||||
SECURITY_CAP_NOAUDIT, true);
|
CAP_OPT_NOAUDIT, true);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
cap_sys_admin = 1;
|
cap_sys_admin = 1;
|
||||||
|
|
||||||
|
@ -3272,11 +3272,11 @@ static int selinux_inode_getattr(const struct path *path)
|
||||||
static bool has_cap_mac_admin(bool audit)
|
static bool has_cap_mac_admin(bool audit)
|
||||||
{
|
{
|
||||||
const struct cred *cred = current_cred();
|
const struct cred *cred = current_cred();
|
||||||
int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT;
|
unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT;
|
||||||
|
|
||||||
if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit))
|
if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts))
|
||||||
return false;
|
return false;
|
||||||
if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true))
|
if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3680,7 +3680,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
|
||||||
case KDSKBENT:
|
case KDSKBENT:
|
||||||
case KDSKBSENT:
|
case KDSKBSENT:
|
||||||
error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
|
error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
|
||||||
SECURITY_CAP_AUDIT, true);
|
CAP_OPT_NONE, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* default case assumes that the command will go
|
/* default case assumes that the command will go
|
||||||
|
|
|
@ -640,7 +640,7 @@ bool smack_privileged_cred(int cap, const struct cred *cred)
|
||||||
struct smack_known_list_elem *sklep;
|
struct smack_known_list_elem *sklep;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT);
|
rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE);
|
||||||
if (rc)
|
if (rc)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue