[PATCH] audit: mark expected switch fall-through
by Gustavo A. R. Silva
In preparation to enabling -Wimplicit-fallthrough, mark switch
cases where we are expecting to fall through.
This patch fixes the following warning:
kernel/auditfilter.c: In function ‘audit_krule_to_data’:
kernel/auditfilter.c:668:7: warning: this statement may fall through [-Wimplicit-fallthrough=]
if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
^
kernel/auditfilter.c:674:3: note: here
default:
^~~~~~~
Warning level 3 was used: -Wimplicit-fallthrough=3
Notice that, in this particular case, the code comment is modified
in accordance with what GCC is expecting to find.
This patch is part of the ongoing efforts to enable
-Wimplicit-fallthrough.
Signed-off-by: Gustavo A. R. Silva <gustavo(a)embeddedor.com>
---
kernel/auditfilter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index add360b46b38..63f8b3f26fab 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -670,7 +670,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
data->values[i] = AUDIT_UID_UNSET;
break;
}
- /* fallthrough if set */
+ /* fall through - if set */
default:
data->values[i] = f->val;
}
--
2.20.1
4 years, 5 months
[RFC PATCH] audit, security: allow LSMs to selectively enable audit collection
by Aaron Goidel
Presently, there is no way for LSMs to enable collection of supplemental
audit records such as path and inode information when a permission denial
occurs. Provide a LSM hook to allow LSMs to selectively enable collection
on a per-task basis, even if the audit configuration would otherwise
disable auditing of a task and/or contains no audit filter rules. If the
hook returns a non-zero result, collect all available audit information. If
the hook generates its own audit record, then supplemental audit
information will be emitted at syscall exit.
In SELinux, we implement this hook by returning the result of a permission
check on the process. If the new process2:audit_enable permission is
allowed by the policy, then audit collection will be enabled for that
process. Otherwise, SELinux will defer to the audit configuration.
Signed-off-by: Aaron Goidel <acgoide(a)tycho.nsa.gov>
---
include/linux/lsm_hooks.h | 7 +++++++
include/linux/security.h | 7 ++++++-
kernel/auditsc.c | 10 +++++++---
security/security.c | 5 +++++
security/selinux/hooks.c | 11 +++++++++++
security/selinux/include/classmap.h | 2 +-
6 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index ead98af9c602..7d70a6759621 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1380,6 +1380,11 @@
* audit_rule_init.
* @lsmrule contains the allocated rule
*
+ * @audit_enable:
+ * Allow the security module to selectively enable audit collection
+ * on permission denials based on whether or not @tsk has the
+ * process2:audit_enable permission.
+ *
* @inode_invalidate_secctx:
* Notify the security module that it must revalidate the security context
* of an inode.
@@ -1800,6 +1805,7 @@ union security_list_options {
int (*audit_rule_known)(struct audit_krule *krule);
int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule);
void (*audit_rule_free)(void *lsmrule);
+ int (*audit_enable)(struct task_struct *tsk);
#endif /* CONFIG_AUDIT */
#ifdef CONFIG_BPF_SYSCALL
@@ -2043,6 +2049,7 @@ struct security_hook_heads {
struct hlist_head audit_rule_known;
struct hlist_head audit_rule_match;
struct hlist_head audit_rule_free;
+ struct hlist_head audit_enable;
#endif /* CONFIG_AUDIT */
#ifdef CONFIG_BPF_SYSCALL
struct hlist_head bpf;
diff --git a/include/linux/security.h b/include/linux/security.h
index 7d9c1da1f659..7be66db8de4e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1719,7 +1719,7 @@ int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
int security_audit_rule_known(struct audit_krule *krule);
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
void security_audit_rule_free(void *lsmrule);
-
+int security_audit_enable(struct task_struct *tsk);
#else
static inline int security_audit_rule_init(u32 field, u32 op, char *rulestr,
@@ -1742,6 +1742,11 @@ static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
static inline void security_audit_rule_free(void *lsmrule)
{ }
+static inline int security_audit_enable(struct task_struct *tsk)
+{
+ return 0;
+}
+
#endif /* CONFIG_SECURITY */
#endif /* CONFIG_AUDIT */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 95ae27edd417..7e052b71bc42 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -906,8 +906,12 @@ int audit_alloc(struct task_struct *tsk)
state = audit_filter_task(tsk, &key);
if (state == AUDIT_DISABLED) {
- clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
- return 0;
+ if (security_audit_enable(tsk)) {
+ state = AUDIT_BUILD_CONTEXT;
+ } else {
+ clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
+ return 0;
+ }
}
if (!(context = audit_alloc_context(state))) {
@@ -1623,7 +1627,7 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
if (state == AUDIT_DISABLED)
return;
- context->dummy = !audit_n_rules;
+ context->dummy = !audit_n_rules && !security_audit_enable(current);
if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
context->prio = 0;
if (auditd_test_task(current))
diff --git a/security/security.c b/security/security.c
index 30687e1366b7..04e160e5d4ab 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2333,6 +2333,11 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
{
return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
}
+
+int security_audit_enable(struct task_struct *tsk)
+{
+ return call_int_hook(audit_enable, 0, tsk);
+}
#endif /* CONFIG_AUDIT */
#ifdef CONFIG_BPF_SYSCALL
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d55571c585ff..88764aa0ab43 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6628,6 +6628,16 @@ static void selinux_ib_free_security(void *ib_sec)
}
#endif
+#ifdef CONFIG_AUDIT
+static int selinux_audit_enable(struct task_struct *tsk)
+{
+ u32 sid = current_sid();
+
+ return !avc_has_perm(&selinux_state, sid, sid, SECCLASS_PROCESS2,
+ PROCESS2__AUDIT_ENABLE, NULL);
+}
+#endif
+
#ifdef CONFIG_BPF_SYSCALL
static int selinux_bpf(int cmd, union bpf_attr *attr,
unsigned int size)
@@ -6999,6 +7009,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
+ LSM_HOOK_INIT(audit_enable, selinux_audit_enable),
#endif
#ifdef CONFIG_BPF_SYSCALL
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 32e9b03be3dd..d7d856cbd486 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -52,7 +52,7 @@ struct security_class_mapping secclass_map[] = {
"execmem", "execstack", "execheap", "setkeycreate",
"setsockcreate", "getrlimit", NULL } },
{ "process2",
- { "nnp_transition", "nosuid_transition", NULL } },
+ { "nnp_transition", "nosuid_transition", "audit_enable", NULL } },
{ "system",
{ "ipc_info", "syslog_read", "syslog_mod",
"syslog_console", "module_request", "module_load", NULL } },
--
2.21.0
5 years, 2 months
[PATCH] audit-testsuite: update the docs for Debian SID/unstable
by Paul Moore
From: Paul Moore <paul(a)paul-moore.com>
Updates include additional packages and instructions on changing
/bin/sh from Dash to BASH.
Signed-off-by: Paul Moore <paul(a)paul-moore.com>
---
README.md | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/README.md b/README.md
index bc20a21..0f6c861 100644
--- a/README.md
+++ b/README.md
@@ -52,12 +52,23 @@ please follow the instructions below.
### Debian Based Systems
+On Debian you need to install a number of dependencies as well as perform some
+additional system configuration. Install the dependencies using the commands
+below:
+
# apt-get install auditd \
build-essential \
libc6-i386 \
+ libc6-dev-i386 \
perl-modules \
netcat
+After the dependencies are installed you should ensure that BASH is installed
+on the system and that /bin/sh points to BASH, not Dash:
+
+ # apt-get install bash
+ # dpkg-reconfigure dash
+
## Execution
Please notice that tests are changing kernel audit rules and hence it might be
5 years, 2 months
[Question] audit_names use after delete in audit_filter_inodes
by Chen Wandun
Hi,
Recently, I hit a use after delete in audit_filter_inodes,
In this case, I found audit_names->list->next is dead000000000100, when enumerate each
audit_names on list context->names_list.
void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
{
struct audit_names *n;
if (audit_pid && tsk->tgid == audit_pid)
return;
rcu_read_lock();
list_for_each_entry(n, &ctx->names_list, list) {
if (audit_filter_inode_name(tsk, n, ctx))
break;
}
rcu_read_unlock();
}
it seem like the audit_names was already delete from context->names_list.
In source code, there is no any protection on context->names_list when read and write,
is there any race in read and write?
Unfortunately, there is no way to reproduce it.
the call stack is below:
[321315.077117] CPU: 6 PID: 8944 Comm: DefSch0100 Tainted: G OE ----V------- 3.10.0-327.62.59.83.w75.x86_64 #1
[321315.077117] Hardware name: OpenStack Foundation OpenStack Nova, BIOS rel-1.8.1-0-g4adadbd-20170107_142945-9_64_246_229 04/01/2014
[321315.113772] task: ffff8804061c4500 ti: ffff8804021d8000 task.ti: ffff8804021d8000
[321315.113772] RIP: 0010:[<ffffffff8110f038>] [<ffffffff8110f038>] audit_filter_inodes+0x68/0x130
[321315.113772] RSP: 0018:ffff8804021dbef0 EFLAGS: 00010297
[321315.113772] RAX: ffff88040632aa48 RBX: ffff88040632a800 RCX: 000000000000000a
[321315.113772] RDX: 00000000000000c0 RSI: ffff88040632a800 RDI: ffff8804061c4500
[321315.132068] RBP: ffff8804021dbf40 R08: 0000000000000000 R09: 0000000000000000
[321315.132068] R10: 00007fd38197ac00 R11: 0000000000000206 R12: dead000000000100
[321315.132068] R13: ffff8804061c4500 R14: 00000000ffffffff R15: ffff88040632a800
[321315.132068] FS: 00007fd38197b700(0000) GS:ffff88053c380000(0000) knlGS:0000000000000000
[321315.132068] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[321315.132068] CR2: 00007fe48936d156 CR3: 0000000098b50000 CR4: 00000000001407e0
[321315.149373] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[321315.149373] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[321315.149373] Stack:
[321315.149373] ffff88040632aa48 ffff8804061c4500 ffff8804021dbf78 ffffffff819a6260
[321315.149373] 00000000aefb5477 ffff88040632a800 00007fd3d6e80690 ffff8804061c4500
[321315.149373] 00007fd38197ac70 00007fd3f218d008 ffff8804021dbf78 ffffffff8110f7d5
[321315.149373] Call Trace:
[321315.149373] [<ffffffff8110f7d5>] __audit_syscall_exit+0x245/0x280
[321315.149373] [<ffffffff8165316b>] sysret_audit+0x17/0x21
[321315.149373] Code: 84 be 00 00 00 4d 8b a7 48 02 00 00 49 8d 87 48 02 00 00 48 89 45 b0 49 39 c4 0f 84 a3 00 00 00 41 be ff ff ff ff 0f 1f 44 00 00 <49> 8b 44 24 20 83 e0 1f 48 c1 e0 04 4c 8d a8 e0 5e df 81 48 8b
[321315.149373] RIP [<ffffffff8110f038>] audit_filter_inodes+0x68/0x130
[321315.149373] RSP <ffff8804021dbef0>
[321315.196242] ---[ end trace e1b43c8e59447f0a ]---
I am unfamiliar with audit. I will be appreciated if you could give me some suggestion.
Thanks
ChenWandun
5 years, 2 months
[RFC PATCH v3] security, capability: pass object information to security_capable
by Aaron Goidel
From: Nicholas Franck <nhfran2(a)tycho.nsa.gov>
At present security_capable does not pass any object information and
therefore can neither audit the particular object nor take it into
account. Augment the security_capable interface to support passing
supplementary data. Use this facility initially to convey the inode for
capability checks relevant to inodes. This only addresses
capable_wrt_inode_uidgid() calls; other capability checks relevant to
inodes will be addressed in subsequent changes. In the future, this will
be further extended to pass object information for other capability
checks such as the target task for CAP_KILL.
In SELinux this new information is leveraged here to perform an
additional inode based check for capabilities relevant to inodes. Since
the inode provided to capable_wrt_inode_uidgid() is a const argument,
this also required propagating const down to dump_common_audit_data() and
dropping the use of d_find_alias() to find an alias for the inode. This
was sketchy to begin with and should be obsoleted by a separate change
that will allow LSMs to trigger audit collection for all file-related
information.
A new security class is defined for the inode capability permission
checks. This is because the existing file-related classes were already
too close to being full to support the addition of these permissions.
This has the limitation of not supporting per-file-class distinctions
(e.g. distinguishing regular files from directories or special files if
they have the same security label). An alternative would be to
instantiate a separate class for every existing file class, or, to widen
access vectors to 64 bits. Neither seems justified.
It would be possible to fold the existing opts argument into this new
supplementary data structure. This was omitted from this change to
minimize changes.
Signed-off-by: Nicholas Franck <nhfran2(a)tycho.nsa.gov>
Signed-off-by: Aaron Goidel <acgoide(a)tycho.nsa.gov>
---
v3:
- No longer change the audit record for capability checks
- Introduce an inode-based check in selinux_capable
- Drop attempts to find dentry when only inode is available
v2:
- Changed order of audit prints so optional information comes second
---
include/linux/capability.h | 7 +++
include/linux/lsm_audit.h | 2 +-
include/linux/lsm_hooks.h | 3 +-
include/linux/security.h | 23 ++++++---
kernel/capability.c | 33 +++++++++----
kernel/seccomp.c | 2 +-
security/apparmor/capability.c | 3 +-
security/apparmor/include/capability.h | 4 +-
security/apparmor/ipc.c | 2 +-
security/apparmor/lsm.c | 5 +-
security/apparmor/resource.c | 2 +-
security/commoncap.c | 11 +++--
security/lsm_audit.c | 10 +---
security/safesetid/lsm.c | 3 +-
security/security.c | 5 +-
security/selinux/hooks.c | 66 +++++++++++++++++++++++---
security/selinux/include/classmap.h | 3 ++
security/smack/smack_access.c | 2 +-
18 files changed, 136 insertions(+), 50 deletions(-)
diff --git a/include/linux/capability.h b/include/linux/capability.h
index ecce0f43c73a..f72de64c179d 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -211,6 +211,8 @@ 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);
+extern bool ns_capable_inode(struct user_namespace *ns, int cap,
+ const struct inode *inode);
#else
static inline bool has_capability(struct task_struct *t, int cap)
{
@@ -246,6 +248,11 @@ static inline bool ns_capable_setid(struct user_namespace *ns, int cap)
{
return true;
}
+static bool ns_capable_inode(struct user_namespace *ns, int cap,
+ const struct inode *inode)
+{
+ 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/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 915330abf6e5..dc7d00c7ee67 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -77,7 +77,7 @@ struct common_audit_data {
union {
struct path path;
struct dentry *dentry;
- struct inode *inode;
+ const struct inode *inode;
struct lsm_network_audit *net;
int cap;
int ipc_id;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index ead98af9c602..3270b8af3498 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1472,7 +1472,8 @@ union security_list_options {
int (*capable)(const struct cred *cred,
struct user_namespace *ns,
int cap,
- unsigned int opts);
+ unsigned int opts,
+ struct cap_aux_data *cad);
int (*quotactl)(int cmds, int type, int id, struct super_block *sb);
int (*quota_on)(struct dentry *dentry);
int (*syslog)(int type);
diff --git a/include/linux/security.h b/include/linux/security.h
index 7d9c1da1f659..a37377065401 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -77,9 +77,18 @@ enum lsm_event {
LSM_POLICY_CHANGE,
};
+
+struct cap_aux_data {
+ char type;
+#define CAP_AUX_DATA_INODE 1
+ union {
+ const struct inode *inode;
+ } u;
+};
+
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
- int cap, unsigned int opts);
+ int cap, unsigned int opts, struct cap_aux_data *cad);
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_traceme(struct task_struct *parent);
@@ -215,9 +224,10 @@ int security_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted);
int security_capable(const struct cred *cred,
- struct user_namespace *ns,
- int cap,
- unsigned int opts);
+ struct user_namespace *ns,
+ int cap,
+ unsigned int opts,
+ struct cap_aux_data *cad);
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
int security_quota_on(struct dentry *dentry);
int security_syslog(int type);
@@ -478,9 +488,10 @@ static inline int security_capset(struct cred *new,
static inline int security_capable(const struct cred *cred,
struct user_namespace *ns,
int cap,
- unsigned int opts)
+ unsigned int opts,
+ struct cap_aux_data *cad)
{
- return cap_capable(cred, ns, cap, opts);
+ return cap_capable(cred, ns, cap, opts, NULL);
}
static inline int security_quotactl(int cmds, int type, int id,
diff --git a/kernel/capability.c b/kernel/capability.c
index 1444f3954d75..c3723443904a 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -297,7 +297,7 @@ bool has_ns_capability(struct task_struct *t,
int ret;
rcu_read_lock();
- ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NONE);
+ ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NONE, NULL);
rcu_read_unlock();
return (ret == 0);
@@ -338,7 +338,7 @@ bool has_ns_capability_noaudit(struct task_struct *t,
int ret;
rcu_read_lock();
- ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NOAUDIT);
+ ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NOAUDIT, NULL);
rcu_read_unlock();
return (ret == 0);
@@ -363,7 +363,8 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
static bool ns_capable_common(struct user_namespace *ns,
int cap,
- unsigned int opts)
+ unsigned int opts,
+ struct cap_aux_data *cad)
{
int capable;
@@ -372,7 +373,7 @@ static bool ns_capable_common(struct user_namespace *ns,
BUG();
}
- capable = security_capable(current_cred(), ns, cap, opts);
+ capable = security_capable(current_cred(), ns, cap, opts, cad);
if (capable == 0) {
current->flags |= PF_SUPERPRIV;
return true;
@@ -393,7 +394,7 @@ static bool ns_capable_common(struct user_namespace *ns,
*/
bool ns_capable(struct user_namespace *ns, int cap)
{
- return ns_capable_common(ns, cap, CAP_OPT_NONE);
+ return ns_capable_common(ns, cap, CAP_OPT_NONE, NULL);
}
EXPORT_SYMBOL(ns_capable);
@@ -411,7 +412,7 @@ EXPORT_SYMBOL(ns_capable);
*/
bool ns_capable_noaudit(struct user_namespace *ns, int cap)
{
- return ns_capable_common(ns, cap, CAP_OPT_NOAUDIT);
+ return ns_capable_common(ns, cap, CAP_OPT_NOAUDIT, NULL);
}
EXPORT_SYMBOL(ns_capable_noaudit);
@@ -430,7 +431,7 @@ EXPORT_SYMBOL(ns_capable_noaudit);
*/
bool ns_capable_setid(struct user_namespace *ns, int cap)
{
- return ns_capable_common(ns, cap, CAP_OPT_INSETID);
+ return ns_capable_common(ns, cap, CAP_OPT_INSETID, NULL);
}
EXPORT_SYMBOL(ns_capable_setid);
@@ -470,7 +471,7 @@ bool file_ns_capable(const struct file *file, struct user_namespace *ns,
if (WARN_ON_ONCE(!cap_valid(cap)))
return false;
- if (security_capable(file->f_cred, ns, cap, CAP_OPT_NONE) == 0)
+ if (security_capable(file->f_cred, ns, cap, CAP_OPT_NONE, NULL) == 0)
return true;
return false;
@@ -503,7 +504,8 @@ bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
{
struct user_namespace *ns = current_user_ns();
- return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode);
+ return ns_capable_inode(ns, cap, inode) &&
+ privileged_wrt_inode_uidgid(ns, inode);
}
EXPORT_SYMBOL(capable_wrt_inode_uidgid);
@@ -524,7 +526,18 @@ bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns)
cred = rcu_dereference(tsk->ptracer_cred);
if (cred)
ret = security_capable(cred, ns, CAP_SYS_PTRACE,
- CAP_OPT_NOAUDIT);
+ CAP_OPT_NOAUDIT, NULL);
rcu_read_unlock();
return (ret == 0);
}
+
+bool ns_capable_inode(struct user_namespace *ns, int cap,
+ const struct inode *inode)
+{
+ struct cap_aux_data cad;
+
+ cad.type = CAP_AUX_DATA_INODE;
+ cad.u.inode = inode;
+ return ns_capable_common(ns, cap, CAP_OPT_NONE, &cad);
+}
+EXPORT_SYMBOL(ns_capable_inode);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 811b4a86cdf6..d59dd7079ece 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -446,7 +446,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
*/
if (!task_no_new_privs(current) &&
security_capable(current_cred(), current_user_ns(),
- CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0)
+ CAP_SYS_ADMIN, CAP_OPT_NOAUDIT, NULL) != 0)
return ERR_PTR(-EACCES);
/* Allocate a new seccomp_filter */
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
index 752f73980e30..eb4a63fa9888 100644
--- a/security/apparmor/capability.c
+++ b/security/apparmor/capability.c
@@ -148,7 +148,8 @@ static int profile_capable(struct aa_profile *profile, int cap,
*
* Returns: 0 on success, or else an error code.
*/
-int aa_capable(struct aa_label *label, int cap, unsigned int opts)
+int aa_capable(struct aa_label *label, int cap, unsigned int opts,
+ struct cap_aux_data *cad)
{
struct aa_profile *profile;
int error = 0;
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
index 1b3663b6ab12..d888f09d76d1 100644
--- a/security/apparmor/include/capability.h
+++ b/security/apparmor/include/capability.h
@@ -20,6 +20,7 @@
#include "apparmorfs.h"
struct aa_label;
+struct cap_aux_data;
/* aa_caps - confinement data for capabilities
* @allowed: capabilities mask
@@ -40,7 +41,8 @@ struct aa_caps {
extern struct aa_sfs_entry aa_sfs_entry_caps[];
-int aa_capable(struct aa_label *label, int cap, unsigned int opts);
+int aa_capable(struct aa_label *label, int cap, unsigned int opts,
+ struct cap_aux_data *cad);
static inline void aa_free_cap_rules(struct aa_caps *caps)
{
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index aacd1e95cb59..deb5267ca695 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -108,7 +108,7 @@ static int profile_tracer_perm(struct aa_profile *tracer,
aad(sa)->peer = tracee;
aad(sa)->request = 0;
aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
- CAP_OPT_NONE);
+ CAP_OPT_NONE, NULL);
return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 87500bde5a92..82790accb679 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -172,14 +172,15 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
}
static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
- int cap, unsigned int opts)
+ int cap, unsigned int opts,
+ struct cap_aux_data *cad)
{
struct aa_label *label;
int error = 0;
label = aa_get_newest_cred_label(cred);
if (!unconfined(label))
- error = aa_capable(label, cap, opts);
+ error = aa_capable(label, cap, opts, cad);
aa_put_label(label);
return error;
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index 552ed09cb47e..9b3d4b4437f2 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
*/
if (label != peer &&
- aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
+ aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT, NULL) != 0)
error = fn_for_each(label, profile,
audit_resource(profile, resource,
new_rlim->rlim_max, peer,
diff --git a/security/commoncap.c b/security/commoncap.c
index c477fb673701..1860ea50f473 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -68,7 +68,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
* 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, unsigned int opts)
+ int cap, unsigned int opts, struct cap_aux_data *cad)
{
struct user_namespace *ns = targ_ns;
@@ -226,7 +226,7 @@ static inline int cap_inh_is_capped(void)
* capability
*/
if (cap_capable(current_cred(), current_cred()->user_ns,
- CAP_SETPCAP, CAP_OPT_NONE) == 0)
+ CAP_SETPCAP, CAP_OPT_NONE, NULL) == 0)
return 0;
return 1;
}
@@ -1211,7 +1211,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|| (cap_capable(current_cred(),
current_cred()->user_ns,
CAP_SETPCAP,
- CAP_OPT_NONE) != 0) /*[4]*/
+ CAP_OPT_NONE,
+ NULL) != 0) /*[4]*/
/*
* [1] no changing of bits that are locked
* [2] no unlocking of locks
@@ -1307,7 +1308,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
int cap_sys_admin = 0;
if (cap_capable(current_cred(), &init_user_ns,
- CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0)
+ CAP_SYS_ADMIN, CAP_OPT_NOAUDIT, NULL) == 0)
cap_sys_admin = 1;
return cap_sys_admin;
@@ -1328,7 +1329,7 @@ int cap_mmap_addr(unsigned long addr)
if (addr < dac_mmap_min_addr) {
ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
- CAP_OPT_NONE);
+ CAP_OPT_NONE, NULL);
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
if (ret == 0)
current->flags |= PF_SUPERPRIV;
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 33028c098ef3..67c2d02cd722 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -288,17 +288,9 @@ static void dump_common_audit_data(struct audit_buffer *ab,
break;
}
case LSM_AUDIT_DATA_INODE: {
- struct dentry *dentry;
- struct inode *inode;
+ const struct inode *inode;
inode = a->u.inode;
- dentry = d_find_alias(inode);
- if (dentry) {
- audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab,
- dentry->d_name.name);
- dput(dentry);
- }
audit_log_format(ab, " dev=");
audit_log_untrustedstring(ab, inode->i_sb->s_id);
audit_log_format(ab, " ino=%lu", inode->i_ino);
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index cecd38e2ac80..c74ed83e9501 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -80,7 +80,8 @@ static bool check_setuid_policy_hashtable_key_value(kuid_t parent,
static int safesetid_security_capable(const struct cred *cred,
struct user_namespace *ns,
int cap,
- unsigned int opts)
+ unsigned int opts,
+ struct cap_aux_data *cad)
{
if (cap == CAP_SETUID &&
check_setuid_policy_hashtable_key(cred->uid)) {
diff --git a/security/security.c b/security/security.c
index 30687e1366b7..e5e0637f43ac 100644
--- a/security/security.c
+++ b/security/security.c
@@ -691,9 +691,10 @@ int security_capset(struct cred *new, const struct cred *old,
int security_capable(const struct cred *cred,
struct user_namespace *ns,
int cap,
- unsigned int opts)
+ unsigned int opts,
+ struct cap_aux_data *cad)
{
- return call_int_hook(capable, 0, cred, ns, cap, opts);
+ return call_int_hook(capable, 0, cred, ns, cap, opts, cad);
}
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d55571c585ff..093d17f9d500 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1620,7 +1620,10 @@ static inline u32 signal_to_av(int sig)
/* Check whether a task is allowed to use a capability. */
static int cred_has_capability(const struct cred *cred,
- int cap, unsigned int opts, bool initns)
+ int cap,
+ unsigned int opts,
+ bool initns,
+ struct cap_aux_data *cad)
{
struct common_audit_data ad;
struct av_decision avd;
@@ -1653,6 +1656,55 @@ static int cred_has_capability(const struct cred *cred,
if (rc2)
return rc2;
}
+
+ if (rc)
+ return rc;
+
+ if (cad && cad->type == CAP_AUX_DATA_INODE) {
+ const struct inode *inode = cad->u.inode;
+ struct inode_security_struct *isec = selinux_inode(inode);
+
+ switch (cap) {
+ case CAP_DAC_OVERRIDE:
+ av = INODE_CAP__DAC_OVERRIDE;
+ break;
+ case CAP_CHOWN:
+ av = INODE_CAP__CHOWN;
+ break;
+ case CAP_FSETID:
+ av = INODE_CAP__FSETID;
+ break;
+ case CAP_DAC_READ_SEARCH:
+ av = INODE_CAP__DAC_READ_SEARCH;
+ break;
+ case CAP_FOWNER:
+ av = INODE_CAP__FOWNER;
+ break;
+ case CAP_SETFCAP:
+ av = INODE_CAP__SETFCAP;
+ break;
+ default:
+ pr_err("SELinux: Unknown capability for inode %d\n",
+ cap);
+ return -EINVAL;
+ }
+
+ rc = avc_has_perm_noaudit(&selinux_state, sid, isec->sid,
+ SECCLASS_INODE_CAP, av, 0, &avd);
+ if (!(opts & CAP_OPT_NOAUDIT)) {
+ int rc2;
+
+ ad.type = LSM_AUDIT_DATA_INODE;
+ ad.u.inode = inode;
+ rc2 = avc_audit(&selinux_state, sid, isec->sid,
+ SECCLASS_INODE_CAP, av, &avd,
+ rc, &ad, 0);
+ if (rc2)
+ return rc2;
+ }
+ }
+
+
return rc;
}
@@ -2167,9 +2219,9 @@ static int selinux_capset(struct cred *new, const struct cred *old,
*/
static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
- int cap, unsigned int opts)
+ int cap, unsigned int opts, struct cap_aux_data *cad)
{
- return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
+ return cred_has_capability(cred, cap, opts, ns == &init_user_ns, cad);
}
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -2243,7 +2295,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
int rc, cap_sys_admin = 0;
rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
- CAP_OPT_NOAUDIT, true);
+ CAP_OPT_NOAUDIT, true, NULL);
if (rc == 0)
cap_sys_admin = 1;
@@ -3103,9 +3155,9 @@ static bool has_cap_mac_admin(bool audit)
const struct cred *cred = current_cred();
unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT;
- if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts))
+ if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts, NULL))
return false;
- if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true))
+ if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true, NULL))
return false;
return true;
}
@@ -3609,7 +3661,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
case KDSKBENT:
case KDSKBSENT:
error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
- CAP_OPT_NONE, true);
+ CAP_OPT_NONE, true, NULL);
break;
/* default case assumes that the command will go
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 32e9b03be3dd..09b3ac77fe97 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -244,6 +244,9 @@ struct security_class_mapping secclass_map[] = {
{"map_create", "map_read", "map_write", "prog_load", "prog_run"} },
{ "xdp_socket",
{ COMMON_SOCK_PERMS, NULL } },
+ { "inode_cap",
+ { "dac_override", "chown", "fsetid", "fowner",
+ "dac_read_search", "setfcap", NULL } },
{ NULL }
};
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index fe2ce3a65822..e961bfe8f00a 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -640,7 +640,7 @@ bool smack_privileged_cred(int cap, const struct cred *cred)
struct smack_known_list_elem *sklep;
int rc;
- rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE);
+ rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE, NULL);
if (rc)
return false;
--
2.21.0
5 years, 2 months
Re: [RFC PATCH v2] security, capability: pass object information to security_capable
by Paul Moore
On Thu, Aug 1, 2019 at 10:43 AM Aaron Goidel <acgoide(a)tycho.nsa.gov> wrote:
> From: Nicholas Franck <nhfran2(a)tycho.nsa.gov>
>
> At present security_capable does not pass any object information
> and therefore can neither audit the particular object nor take it
> into account. Augment the security_capable interface to support
> passing supplementary data. Use this facility initially to convey
> the inode for capability checks relevant to inodes. This only
> addresses capable_wrt_inode_uidgid calls; other capability checks
> relevant to inodes will be addressed in subsequent changes. In the
> future, this will be further extended to pass object information for
> other capability checks such as the target task for CAP_KILL.
>
> In SELinux this new information is leveraged here to include the inode
> in the audit message. In the future, it could also be used to perform
> a per inode capability checks.
>
> It would be possible to fold the existing opts argument into this new
> supplementary data structure. This was omitted from this change to
> minimize changes.
>
> Signed-off-by: Nicholas Franck <nhfran2(a)tycho.nsa.gov>
> Signed-off-by: Aaron Goidel <acgoide(a)tycho.nsa.gov>
> ---
> v2:
> - Changed order of audit prints so optional information comes second
> ---
> include/linux/capability.h | 7 ++++++
> include/linux/lsm_audit.h | 5 +++-
> include/linux/lsm_hooks.h | 3 ++-
> include/linux/security.h | 23 +++++++++++++-----
> kernel/capability.c | 33 ++++++++++++++++++--------
> kernel/seccomp.c | 2 +-
> security/apparmor/capability.c | 8 ++++---
> security/apparmor/include/capability.h | 4 +++-
> security/apparmor/ipc.c | 2 +-
> security/apparmor/lsm.c | 5 ++--
> security/apparmor/resource.c | 2 +-
> security/commoncap.c | 11 +++++----
> security/lsm_audit.c | 21 ++++++++++++++--
> security/safesetid/lsm.c | 3 ++-
> security/security.c | 5 ++--
> security/selinux/hooks.c | 20 +++++++++-------
> security/smack/smack_access.c | 2 +-
> 17 files changed, 110 insertions(+), 46 deletions(-)
You should CC the linux-audit list, I've added them on this mail.
I had hoped to see some thought put into the idea of dynamically
emitting the proper audit records as I mentioned in the previous patch
set, but regardless there are some comments on this code as written
...
> diff --git a/security/lsm_audit.c b/security/lsm_audit.c
> index 33028c098ef3..18cc7c956b69 100644
> --- a/security/lsm_audit.c
> +++ b/security/lsm_audit.c
> @@ -229,9 +229,26 @@ static void dump_common_audit_data(struct audit_buffer *ab,
> case LSM_AUDIT_DATA_IPC:
> audit_log_format(ab, " key=%d ", a->u.ipc_id);
> break;
> - case LSM_AUDIT_DATA_CAP:
> - audit_log_format(ab, " capability=%d ", a->u.cap);
> + case LSM_AUDIT_DATA_CAP: {
> + const struct inode *inode;
> +
> + audit_log_format(ab, " capability=%d ", a->u.cap_struct.cap);
> + if (a->u.cap_struct.cad) {
> + switch (a->u.cap_struct.cad->type) {
> + case CAP_AUX_DATA_INODE: {
> + inode = a->u.cap_struct.cad->u.inode;
> +
> + audit_log_format(ab, " dev=");
> + audit_log_untrustedstring(ab,
> + inode->i_sb->s_id);
> + audit_log_format(ab, " ino=%lu",
> + inode->i_ino);
> + break;
> + }
Since you are declaring "inode" further up, there doesn't appear to be
any need for the CAP_AUX_DATA_INODE braces, please remove them.
The general recommended practice when it comes to "sometimes" fields
in an audit record, is to always record them in the record, but use a
value of "?" when there is nothing relevant to record. For example,
when *not* recording inode information you would do something like the
following:
audit_log_format(ab, " dev=? ino=?");
> + }
> + }
> break;
> + }
> case LSM_AUDIT_DATA_PATH: {
> struct inode *inode;
>
--
paul moore
www.paul-moore.com
5 years, 2 months
Number of TTY events vs Number of USER_TTY events
by Smith, Gary R
Good afternoon,
I have TTY auditing set up on a number of hosts using pam_tty_audit for the root account. I have this line in a PAM file to enable it:
session required pam_tty_audit.so disable=* enable=root
In looking at the reports from aureport and ausearch, the number of TTY events is always equal to the number of USER_TTY events. For instance:
# ausearch -i -m TTY -ts today | wc -l ; ausearch -i -m USER_TTY -ts today | wc -l
20
20
I started wondering, “Are there always the same number of these two event types?” I tried constructing some synthetic cases to see if there is a case where there isn’t an equal number of the two events. I couldn’t construct such a case. Is there a case of cases where the two type event types aren’t of equal number?
Thanks for your help,
Gary Smith
5 years, 2 months
Query - System Calls Arguments in Linux Audit Kernel
by Muhammad Adil Inam
To whom it may concern,
Hi,
I am a CS research assistant currently working at Lahore University of Management Sciences (LUMS), Pakistan. The project I am working on involves understanding and working with the Linux Audit Kernel.
As you know, linux-audit logs all the syscall arguments as a1, a2, a3, a4 as unsigned longs. In the case of some syscall, such as WRITE, the second argument, a2, stores the pointer to a buffer, where the buffer contains the content being written. I have been trying to deference the buffer from its address stored in a2. I am dereferencing the buffer currently in kernel/auditsc.c and dumping the dereferenced contents of a2 to printk. However, after building the customized kernel, auditd fails probably due to invalid pointer dereferencing.
I am confused regarding the scope of that pointer variable stored in a2. I have two questions:
1) Is it possible to deference the syscall arguments in the Linux kernel, given the buffer was initially sent by the process that initiated the syscall?
2) If it is possible to do so, what is the right way to go about it. What is the right file to work if the goal is to dereference the address stored in one of the SYSCALL arguments?
Really looking forward to hearing back from you.
Best Regards,
Adil
5 years, 2 months