Seccomp received improved logging controls in v4.14. Applications can opt into
logging of "handled" actions (SECCOMP_RET_TRAP, SECCOMP_RET_TRACE,
SECCOMP_RET_ERRNO) using the SECCOMP_FILTER_FLAG_LOG bit when loading filters.
They can also debug filter matching with the new SECCOMP_RET_LOG action.
Administrators can prevent specific actions from being logged using the
kernel.seccomp.actions_logged sysctl.
However, one corner case intentionally wasn't addressed in those v4.14 changes.
When a process is being inspected by the audit subsystem, seccomp's decision
making for logging ignores the new controls and unconditionally logs every
action taken except for SECCOMP_RET_ALLOW. This isn't particularly useful since
many existing applications don't intend to log handled actions due to them
occurring very frequently. This amount of logging fills the audit logs without
providing many benefits now that application authors have fine grained controls
at their disposal.
This patch set aligns the seccomp logging behavior for both audited and
non-audited processes. It also emits an audit record, if auditing is enabled,
when the kernel.seccomp.actions_logged sysctl is written to so that there's a
paper trail when entire actions are quieted.
Changes in v3:
* Patch 3
- Never drop a field when emitting the audit record
- Use the value "?" for the actions field when an error occurred while
writing to the sysctl
- Use the value "?" for the actions and/or old-actions fields when a failure
to translate actions to names
- Use the value "(none)" for the actions and/or old-actions fields when no
actions are specified
+ This is possible when writing an empty string to the sysctl
- Update the commit message to note the new values and give an example of
when an empty string is written
* Patch 4
- Adjust the control flow of seccomp_log() to exit early if nothing should be
logged
Changes in v2:
* Patch 2
- New patch, allowing for a configurable separator between action names
* Patch 3
- The value of the actions field in the audit record now uses a comma instead
of a space
- The value of the actions field in the audit record is no longer enclosed in
quotes
- audit_log_start() is called with the current processes' audit_context in
audit_seccomp_actions_logged()
- audit_seccomp_actions_logged() no longer records the pid, uid, auid, tty,
ses, task context, comm, or executable path
- The new and old value of seccomp_actions_logged is recorded in the
AUDIT_CONFIG_CHANGE record
- The value of the "res" field in the CONFIG_CHANGE audit record is corrected
(1 indicates success, 0 failure)
- Updated patch 3's commit message to reflect the updated audit record format
in the examples
* Patch 4
- A function comment for audit_seccomp() was added to explain, among other
things, that event filtering is performed in seccomp_log()
Tyler
Break the read and write paths of the kernel.seccomp.actions_logged
sysctl into separate functions to maintain readability. An upcoming
change will need to audit writes, but not reads, of this sysctl which
would introduce too many conditional code paths on whether or not the
'write' parameter evaluates to true.
Signed-off-by: Tyler Hicks <[email protected]>
---
kernel/seccomp.c | 60 +++++++++++++++++++++++++++++++++++---------------------
1 file changed, 38 insertions(+), 22 deletions(-)
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index dc77548..f4afe67 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1199,48 +1199,64 @@ static bool seccomp_actions_logged_from_names(u32 *actions_logged, char *names)
return true;
}
-static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
- void __user *buffer, size_t *lenp,
- loff_t *ppos)
+static int read_actions_logged(struct ctl_table *ro_table, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
{
char names[sizeof(seccomp_actions_avail)];
struct ctl_table table;
+
+ memset(names, 0, sizeof(names));
+
+ if (!seccomp_names_from_actions_logged(names, sizeof(names),
+ seccomp_actions_logged))
+ return -EINVAL;
+
+ table = *ro_table;
+ table.data = names;
+ table.maxlen = sizeof(names);
+ return proc_dostring(&table, 0, buffer, lenp, ppos);
+}
+
+static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ char names[sizeof(seccomp_actions_avail)];
+ struct ctl_table table;
+ u32 actions_logged;
int ret;
- if (write && !capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
memset(names, 0, sizeof(names));
- if (!write) {
- if (!seccomp_names_from_actions_logged(names, sizeof(names),
- seccomp_actions_logged))
- return -EINVAL;
- }
-
table = *ro_table;
table.data = names;
table.maxlen = sizeof(names);
- ret = proc_dostring(&table, write, buffer, lenp, ppos);
+ ret = proc_dostring(&table, 1, buffer, lenp, ppos);
if (ret)
return ret;
- if (write) {
- u32 actions_logged;
-
- if (!seccomp_actions_logged_from_names(&actions_logged,
- table.data))
- return -EINVAL;
-
- if (actions_logged & SECCOMP_LOG_ALLOW)
- return -EINVAL;
+ if (!seccomp_actions_logged_from_names(&actions_logged, table.data))
+ return -EINVAL;
- seccomp_actions_logged = actions_logged;
- }
+ if (actions_logged & SECCOMP_LOG_ALLOW)
+ return -EINVAL;
+ seccomp_actions_logged = actions_logged;
return 0;
}
+static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ if (write)
+ return write_actions_logged(ro_table, buffer, lenp, ppos);
+ else
+ return read_actions_logged(ro_table, buffer, lenp, ppos);
+}
+
static struct ctl_path seccomp_sysctl_path[] = {
{ .procname = "kernel", },
{ .procname = "seccomp", },
--
2.7.4
Seccomp logging for "handled" actions such as RET_TRAP, RET_TRACE, or
RET_ERRNO can be very noisy for processes that are being audited. This
patch modifies the seccomp logging behavior to treat processes that are
being inspected via the audit subsystem the same as processes that
aren't under inspection. Handled actions will no longer be logged just
because the process is being inspected. Since v4.14, applications have
the ability to request logging of handled actions by using the
SECCOMP_FILTER_FLAG_LOG flag when loading seccomp filters.
With this patch, the logic for deciding if an action will be logged is:
if action == RET_ALLOW:
do not log
else if action not in actions_logged:
do not log
else if action == RET_KILL:
log
else if action == RET_LOG:
log
else if filter-requests-logging:
log
else:
do not log
Reported-by: Steve Grubb <[email protected]>
Signed-off-by: Tyler Hicks <[email protected]>
---
Documentation/userspace-api/seccomp_filter.rst | 7 -------
include/linux/audit.h | 10 +---------
kernel/auditsc.c | 14 +++++++++++++-
kernel/seccomp.c | 17 +++++++----------
4 files changed, 21 insertions(+), 27 deletions(-)
diff --git a/Documentation/userspace-api/seccomp_filter.rst b/Documentation/userspace-api/seccomp_filter.rst
index 099c412..82a468b 100644
--- a/Documentation/userspace-api/seccomp_filter.rst
+++ b/Documentation/userspace-api/seccomp_filter.rst
@@ -207,13 +207,6 @@ directory. Here's a description of each file in that directory:
to the file do not need to be in ordered form but reads from the file
will be ordered in the same way as the actions_avail sysctl.
- It is important to note that the value of ``actions_logged`` does not
- prevent certain actions from being logged when the audit subsystem is
- configured to audit a task. If the action is not found in
- ``actions_logged`` list, the final decision on whether to audit the
- action for that task is ultimately left up to the audit subsystem to
- decide for all seccomp return values other than ``SECCOMP_RET_ALLOW``.
-
The ``allow`` string is not accepted in the ``actions_logged`` sysctl
as it is not possible to log ``SECCOMP_RET_ALLOW`` actions. Attempting
to write ``allow`` to the sysctl will result in an EINVAL being
diff --git a/include/linux/audit.h b/include/linux/audit.h
index d4e35e7..b639cf1 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -232,7 +232,7 @@ extern void __audit_file(const struct file *);
extern void __audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type);
-extern void __audit_seccomp(unsigned long syscall, long signr, int code);
+extern void audit_seccomp(unsigned long syscall, long signr, int code);
extern void audit_seccomp_actions_logged(const char *names,
const char *old_names, int res);
extern void __audit_ptrace(struct task_struct *t);
@@ -304,12 +304,6 @@ static inline void audit_inode_child(struct inode *parent,
}
void audit_core_dumps(long signr);
-static inline void audit_seccomp(unsigned long syscall, long signr, int code)
-{
- if (audit_enabled && unlikely(!audit_dummy_context()))
- __audit_seccomp(syscall, signr, code);
-}
-
static inline void audit_ptrace(struct task_struct *t)
{
if (unlikely(!audit_dummy_context()))
@@ -500,8 +494,6 @@ static inline void audit_inode_child(struct inode *parent,
{ }
static inline void audit_core_dumps(long signr)
{ }
-static inline void __audit_seccomp(unsigned long syscall, long signr, int code)
-{ }
static inline void audit_seccomp(unsigned long syscall, long signr, int code)
{ }
static inline void audit_seccomp_actions_logged(const char *names,
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 5195a29..15c20ba 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2464,7 +2464,19 @@ void audit_core_dumps(long signr)
audit_log_end(ab);
}
-void __audit_seccomp(unsigned long syscall, long signr, int code)
+/**
+ * audit_seccomp - record information about a seccomp action
+ * @syscall: syscall number
+ * @signr: signal value
+ * @code: the seccomp action
+ *
+ * Record the information associated with a seccomp action. Event filtering for
+ * seccomp actions that are not to be logged is done in seccomp_log().
+ * Therefore, this function forces auditing independent of the audit_enabled
+ * and dummy context state because seccomp actions should be logged even when
+ * audit is not in use.
+ */
+void audit_seccomp(unsigned long syscall, long signr, int code)
{
struct audit_buffer *ab;
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index f5630d1..5386749 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -584,18 +584,15 @@ static inline void seccomp_log(unsigned long syscall, long signr, u32 action,
}
/*
- * Force an audit message to be emitted when the action is RET_KILL_*,
- * RET_LOG, or the FILTER_FLAG_LOG bit was set and the action is
- * allowed to be logged by the admin.
+ * Emit an audit message when the action is RET_KILL_*, RET_LOG, or the
+ * FILTER_FLAG_LOG bit was set. The admin has the ability to silence
+ * any action from being logged by removing the action name from the
+ * seccomp_actions_logged sysctl.
*/
- if (log)
- return __audit_seccomp(syscall, signr, action);
+ if (!log)
+ return;
- /*
- * Let the audit subsystem decide if the action should be audited based
- * on whether the current task itself is being audited.
- */
- return audit_seccomp(syscall, signr, action);
+ audit_seccomp(syscall, signr, action);
}
/*
--
2.7.4
The function that converts a bitmask of seccomp actions that are
allowed to be logged is currently only used for constructing the display
string for the kernel.seccomp.actions_logged sysctl. That string wants a
space character to be used for the separator between actions.
A future patch will make use of the same function for building a string
that will be sent to the audit subsystem for tracking modifications to
the kernel.seccomp.actions_logged sysctl. That string will need to use a
comma as a separator. This patch allows the separator character to be
configurable to meet both needs.
Signed-off-by: Tyler Hicks <[email protected]>
---
kernel/seccomp.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index f4afe67..b36ac1e 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1135,10 +1135,11 @@ static const struct seccomp_log_name seccomp_log_names[] = {
};
static bool seccomp_names_from_actions_logged(char *names, size_t size,
- u32 actions_logged)
+ u32 actions_logged,
+ const char *sep)
{
const struct seccomp_log_name *cur;
- bool append_space = false;
+ bool append_sep = false;
for (cur = seccomp_log_names; cur->name && size; cur++) {
ssize_t ret;
@@ -1146,15 +1147,15 @@ static bool seccomp_names_from_actions_logged(char *names, size_t size,
if (!(actions_logged & cur->log))
continue;
- if (append_space) {
- ret = strscpy(names, " ", size);
+ if (append_sep) {
+ ret = strscpy(names, sep, size);
if (ret < 0)
return false;
names += ret;
size -= ret;
} else
- append_space = true;
+ append_sep = true;
ret = strscpy(names, cur->name, size);
if (ret < 0)
@@ -1208,7 +1209,7 @@ static int read_actions_logged(struct ctl_table *ro_table, void __user *buffer,
memset(names, 0, sizeof(names));
if (!seccomp_names_from_actions_logged(names, sizeof(names),
- seccomp_actions_logged))
+ seccomp_actions_logged, " "))
return -EINVAL;
table = *ro_table;
--
2.7.4
The decision to log a seccomp action will always be subject to the
value of the kernel.seccomp.actions_logged sysctl, even for processes
that are being inspected via the audit subsystem, in an upcoming patch.
Therefore, we need to emit an audit record on attempts at writing to the
actions_logged sysctl when auditing is enabled.
This patch updates the write handler for the actions_logged sysctl to
emit an audit record on attempts to write to the sysctl. Successful
writes to the sysctl will result in a record that includes a normalized
list of logged actions in the "actions" field and a "res" field equal to
1. Unsuccessful writes to the sysctl will result in a record that
doesn't include the "actions" field and has a "res" field equal to 0.
Not all unsuccessful writes to the sysctl are audited. For example, an
audit record will not be emitted if an unprivileged process attempts to
open the sysctl file for reading since that access control check is not
part of the sysctl's write handler.
Below are some example audit records when writing various strings to the
actions_logged sysctl.
Writing "not-a-real-action", when the kernel.seccomp.actions_logged
sysctl previously was "kill_process kill_thread trap errno trace log",
emits this audit record:
type=CONFIG_CHANGE msg=audit(1525392371.454:120): op=seccomp-logging
actions=? old-actions=kill_process,kill_thread,trap,errno,trace,log
res=0
If you then write "kill_process kill_thread errno trace log", this audit
record is emitted:
type=CONFIG_CHANGE msg=audit(1525392401.645:126): op=seccomp-logging
actions=kill_process,kill_thread,errno,trace,log
old-actions=kill_process,kill_thread,trap,errno,trace,log res=1
If you then write "log log errno trace kill_process kill_thread", which
is unordered and contains the log action twice, it results in the same
actions value as the previous record:
type=CONFIG_CHANGE msg=audit(1525392436.354:132): op=seccomp-logging
actions=kill_process,kill_thread,errno,trace,log
old-actions=kill_process,kill_thread,errno,trace,log res=1
If you then write an empty string to the sysctl, this audit record is
emitted:
type=CONFIG_CHANGE msg=audit(1525392494.413:138): op=seccomp-logging
actions=(none) old-actions=kill_process,kill_thread,errno,trace,log
res=1
No audit records are generated when reading the actions_logged sysctl.
Suggested-by: Steve Grubb <[email protected]>
Signed-off-by: Tyler Hicks <[email protected]>
---
include/linux/audit.h | 5 +++++
kernel/auditsc.c | 20 ++++++++++++++++++
kernel/seccomp.c | 58 +++++++++++++++++++++++++++++++++++++++++++--------
3 files changed, 74 insertions(+), 9 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 75d5b03..d4e35e7 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -233,6 +233,8 @@ extern void __audit_inode_child(struct inode *parent,
const struct dentry *dentry,
const unsigned char type);
extern void __audit_seccomp(unsigned long syscall, long signr, int code);
+extern void audit_seccomp_actions_logged(const char *names,
+ const char *old_names, int res);
extern void __audit_ptrace(struct task_struct *t);
static inline bool audit_dummy_context(void)
@@ -502,6 +504,9 @@ static inline void __audit_seccomp(unsigned long syscall, long signr, int code)
{ }
static inline void audit_seccomp(unsigned long syscall, long signr, int code)
{ }
+static inline void audit_seccomp_actions_logged(const char *names,
+ const char *old_names, int res)
+{ }
static inline int auditsc_get_stamp(struct audit_context *ctx,
struct timespec64 *t, unsigned int *serial)
{
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4e0a4ac..5195a29 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2478,6 +2478,26 @@ void __audit_seccomp(unsigned long syscall, long signr, int code)
audit_log_end(ab);
}
+void audit_seccomp_actions_logged(const char *names, const char *old_names,
+ int res)
+{
+ struct audit_buffer *ab;
+
+ if (!audit_enabled)
+ return;
+
+ ab = audit_log_start(current->audit_context, GFP_KERNEL,
+ AUDIT_CONFIG_CHANGE);
+ if (unlikely(!ab))
+ return;
+
+ audit_log_format(ab, "op=seccomp-logging");
+ audit_log_format(ab, " actions=%s", names);
+ audit_log_format(ab, " old-actions=%s", old_names);
+ audit_log_format(ab, " res=%d", res);
+ audit_log_end(ab);
+}
+
struct list_head *audit_killed_trees(void)
{
struct audit_context *ctx = current->audit_context;
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index b36ac1e..f5630d1 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1219,11 +1219,10 @@ static int read_actions_logged(struct ctl_table *ro_table, void __user *buffer,
}
static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer,
- size_t *lenp, loff_t *ppos)
+ size_t *lenp, loff_t *ppos, u32 *actions_logged)
{
char names[sizeof(seccomp_actions_avail)];
struct ctl_table table;
- u32 actions_logged;
int ret;
if (!capable(CAP_SYS_ADMIN))
@@ -1238,24 +1237,65 @@ static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer,
if (ret)
return ret;
- if (!seccomp_actions_logged_from_names(&actions_logged, table.data))
+ if (!seccomp_actions_logged_from_names(actions_logged, table.data))
return -EINVAL;
- if (actions_logged & SECCOMP_LOG_ALLOW)
+ if (*actions_logged & SECCOMP_LOG_ALLOW)
return -EINVAL;
- seccomp_actions_logged = actions_logged;
+ seccomp_actions_logged = *actions_logged;
return 0;
}
+static void audit_actions_logged(u32 actions_logged, u32 old_actions_logged,
+ int ret)
+{
+ char names[sizeof(seccomp_actions_avail)];
+ char old_names[sizeof(seccomp_actions_avail)];
+ const char *new = names;
+ const char *old = old_names;
+
+ if (!audit_enabled)
+ return;
+
+ memset(names, 0, sizeof(names));
+ memset(old_names, 0, sizeof(old_names));
+
+ if (ret)
+ new = "?";
+ else if (!actions_logged)
+ new = "(none)";
+ else if (!seccomp_names_from_actions_logged(names, sizeof(names),
+ actions_logged, ","))
+ new = "?";
+
+ if (!old_actions_logged)
+ old = "(none)";
+ else if (!seccomp_names_from_actions_logged(old_names,
+ sizeof(old_names),
+ old_actions_logged, ","))
+ old = "?";
+
+ return audit_seccomp_actions_logged(new, old, !ret);
+}
+
static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
- if (write)
- return write_actions_logged(ro_table, buffer, lenp, ppos);
- else
- return read_actions_logged(ro_table, buffer, lenp, ppos);
+ int ret;
+
+ if (write) {
+ u32 actions_logged = 0;
+ u32 old_actions_logged = seccomp_actions_logged;
+
+ ret = write_actions_logged(ro_table, buffer, lenp, ppos,
+ &actions_logged);
+ audit_actions_logged(actions_logged, old_actions_logged, ret);
+ } else
+ ret = read_actions_logged(ro_table, buffer, lenp, ppos);
+
+ return ret;
}
static struct ctl_path seccomp_sysctl_path[] = {
--
2.7.4
On Thursday, May 3, 2018 9:08:14 PM EDT Tyler Hicks wrote:
> The decision to log a seccomp action will always be subject to the
> value of the kernel.seccomp.actions_logged sysctl, even for processes
> that are being inspected via the audit subsystem, in an upcoming patch.
> Therefore, we need to emit an audit record on attempts at writing to the
> actions_logged sysctl when auditing is enabled.
>
> This patch updates the write handler for the actions_logged sysctl to
> emit an audit record on attempts to write to the sysctl. Successful
> writes to the sysctl will result in a record that includes a normalized
> list of logged actions in the "actions" field and a "res" field equal to
> 1. Unsuccessful writes to the sysctl will result in a record that
> doesn't include the "actions" field and has a "res" field equal to 0.
>
> Not all unsuccessful writes to the sysctl are audited. For example, an
> audit record will not be emitted if an unprivileged process attempts to
> open the sysctl file for reading since that access control check is not
> part of the sysctl's write handler.
>
> Below are some example audit records when writing various strings to the
> actions_logged sysctl.
>
> Writing "not-a-real-action", when the kernel.seccomp.actions_logged
> sysctl previously was "kill_process kill_thread trap errno trace log",
> emits this audit record:
>
> type=CONFIG_CHANGE msg=audit(1525392371.454:120): op=seccomp-logging
> actions=? old-actions=kill_process,kill_thread,trap,errno,trace,log
> res=0
>
> If you then write "kill_process kill_thread errno trace log", this audit
> record is emitted:
>
> type=CONFIG_CHANGE msg=audit(1525392401.645:126): op=seccomp-logging
> actions=kill_process,kill_thread,errno,trace,log
> old-actions=kill_process,kill_thread,trap,errno,trace,log res=1
>
> If you then write "log log errno trace kill_process kill_thread", which
> is unordered and contains the log action twice, it results in the same
> actions value as the previous record:
>
> type=CONFIG_CHANGE msg=audit(1525392436.354:132): op=seccomp-logging
> actions=kill_process,kill_thread,errno,trace,log
> old-actions=kill_process,kill_thread,errno,trace,log res=1
>
> If you then write an empty string to the sysctl, this audit record is
> emitted:
>
> type=CONFIG_CHANGE msg=audit(1525392494.413:138): op=seccomp-logging
> actions=(none) old-actions=kill_process,kill_thread,errno,trace,log
> res=1
>
> No audit records are generated when reading the actions_logged sysctl.
This appears to cover all the corner cases we talked about. ACK for the
format of the records.
Thanks,
-Steve
> Suggested-by: Steve Grubb <[email protected]>
> Signed-off-by: Tyler Hicks <[email protected]>
> ---
> include/linux/audit.h | 5 +++++
> kernel/auditsc.c | 20 ++++++++++++++++++
> kernel/seccomp.c | 58
> +++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 74
> insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index 75d5b03..d4e35e7 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -233,6 +233,8 @@ extern void __audit_inode_child(struct inode *parent,
> const struct dentry *dentry,
> const unsigned char type);
> extern void __audit_seccomp(unsigned long syscall, long signr, int code);
> +extern void audit_seccomp_actions_logged(const char *names,
> + const char *old_names, int res);
> extern void __audit_ptrace(struct task_struct *t);
>
> static inline bool audit_dummy_context(void)
> @@ -502,6 +504,9 @@ static inline void __audit_seccomp(unsigned long
> syscall, long signr, int code) { }
> static inline void audit_seccomp(unsigned long syscall, long signr, int
> code) { }
> +static inline void audit_seccomp_actions_logged(const char *names,
> + const char *old_names, int res)
> +{ }
> static inline int auditsc_get_stamp(struct audit_context *ctx,
> struct timespec64 *t, unsigned int *serial)
> {
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 4e0a4ac..5195a29 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2478,6 +2478,26 @@ void __audit_seccomp(unsigned long syscall, long
> signr, int code) audit_log_end(ab);
> }
>
> +void audit_seccomp_actions_logged(const char *names, const char
> *old_names, + int res)
> +{
> + struct audit_buffer *ab;
> +
> + if (!audit_enabled)
> + return;
> +
> + ab = audit_log_start(current->audit_context, GFP_KERNEL,
> + AUDIT_CONFIG_CHANGE);
> + if (unlikely(!ab))
> + return;
> +
> + audit_log_format(ab, "op=seccomp-logging");
> + audit_log_format(ab, " actions=%s", names);
> + audit_log_format(ab, " old-actions=%s", old_names);
> + audit_log_format(ab, " res=%d", res);
> + audit_log_end(ab);
> +}
> +
> struct list_head *audit_killed_trees(void)
> {
> struct audit_context *ctx = current->audit_context;
> diff --git a/kernel/seccomp.c b/kernel/seccomp.c
> index b36ac1e..f5630d1 100644
> --- a/kernel/seccomp.c
> +++ b/kernel/seccomp.c
> @@ -1219,11 +1219,10 @@ static int read_actions_logged(struct ctl_table
> *ro_table, void __user *buffer, }
>
> static int write_actions_logged(struct ctl_table *ro_table, void __user
> *buffer, - size_t *lenp, loff_t *ppos)
> + size_t *lenp, loff_t *ppos, u32 *actions_logged)
> {
> char names[sizeof(seccomp_actions_avail)];
> struct ctl_table table;
> - u32 actions_logged;
> int ret;
>
> if (!capable(CAP_SYS_ADMIN))
> @@ -1238,24 +1237,65 @@ static int write_actions_logged(struct ctl_table
> *ro_table, void __user *buffer, if (ret)
> return ret;
>
> - if (!seccomp_actions_logged_from_names(&actions_logged, table.data))
> + if (!seccomp_actions_logged_from_names(actions_logged, table.data))
> return -EINVAL;
>
> - if (actions_logged & SECCOMP_LOG_ALLOW)
> + if (*actions_logged & SECCOMP_LOG_ALLOW)
> return -EINVAL;
>
> - seccomp_actions_logged = actions_logged;
> + seccomp_actions_logged = *actions_logged;
> return 0;
> }
>
> +static void audit_actions_logged(u32 actions_logged, u32
> old_actions_logged, + int ret)
> +{
> + char names[sizeof(seccomp_actions_avail)];
> + char old_names[sizeof(seccomp_actions_avail)];
> + const char *new = names;
> + const char *old = old_names;
> +
> + if (!audit_enabled)
> + return;
> +
> + memset(names, 0, sizeof(names));
> + memset(old_names, 0, sizeof(old_names));
> +
> + if (ret)
> + new = "?";
> + else if (!actions_logged)
> + new = "(none)";
> + else if (!seccomp_names_from_actions_logged(names, sizeof(names),
> + actions_logged, ","))
> + new = "?";
> +
> + if (!old_actions_logged)
> + old = "(none)";
> + else if (!seccomp_names_from_actions_logged(old_names,
> + sizeof(old_names),
> + old_actions_logged, ","))
> + old = "?";
> +
> + return audit_seccomp_actions_logged(new, old, !ret);
> +}
> +
> static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int
> write, void __user *buffer, size_t *lenp,
> loff_t *ppos)
> {
> - if (write)
> - return write_actions_logged(ro_table, buffer, lenp, ppos);
> - else
> - return read_actions_logged(ro_table, buffer, lenp, ppos);
> + int ret;
> +
> + if (write) {
> + u32 actions_logged = 0;
> + u32 old_actions_logged = seccomp_actions_logged;
> +
> + ret = write_actions_logged(ro_table, buffer, lenp, ppos,
> + &actions_logged);
> + audit_actions_logged(actions_logged, old_actions_logged, ret);
> + } else
> + ret = read_actions_logged(ro_table, buffer, lenp, ppos);
> +
> + return ret;
> }
>
> static struct ctl_path seccomp_sysctl_path[] = {
On Thu, May 3, 2018 at 9:08 PM, Tyler Hicks <[email protected]> wrote:
> Seccomp received improved logging controls in v4.14. Applications can opt into
> logging of "handled" actions (SECCOMP_RET_TRAP, SECCOMP_RET_TRACE,
> SECCOMP_RET_ERRNO) using the SECCOMP_FILTER_FLAG_LOG bit when loading filters.
> They can also debug filter matching with the new SECCOMP_RET_LOG action.
> Administrators can prevent specific actions from being logged using the
> kernel.seccomp.actions_logged sysctl.
>
> However, one corner case intentionally wasn't addressed in those v4.14 changes.
> When a process is being inspected by the audit subsystem, seccomp's decision
> making for logging ignores the new controls and unconditionally logs every
> action taken except for SECCOMP_RET_ALLOW. This isn't particularly useful since
> many existing applications don't intend to log handled actions due to them
> occurring very frequently. This amount of logging fills the audit logs without
> providing many benefits now that application authors have fine grained controls
> at their disposal.
>
> This patch set aligns the seccomp logging behavior for both audited and
> non-audited processes. It also emits an audit record, if auditing is enabled,
> when the kernel.seccomp.actions_logged sysctl is written to so that there's a
> paper trail when entire actions are quieted.
>
> Changes in v3:
> * Patch 3
> - Never drop a field when emitting the audit record
> - Use the value "?" for the actions field when an error occurred while
> writing to the sysctl
> - Use the value "?" for the actions and/or old-actions fields when a failure
> to translate actions to names
> - Use the value "(none)" for the actions and/or old-actions fields when no
> actions are specified
> + This is possible when writing an empty string to the sysctl
> - Update the commit message to note the new values and give an example of
> when an empty string is written
> * Patch 4
> - Adjust the control flow of seccomp_log() to exit early if nothing should be
> logged
>
> Changes in v2:
> * Patch 2
> - New patch, allowing for a configurable separator between action names
> * Patch 3
> - The value of the actions field in the audit record now uses a comma instead
> of a space
> - The value of the actions field in the audit record is no longer enclosed in
> quotes
> - audit_log_start() is called with the current processes' audit_context in
> audit_seccomp_actions_logged()
> - audit_seccomp_actions_logged() no longer records the pid, uid, auid, tty,
> ses, task context, comm, or executable path
> - The new and old value of seccomp_actions_logged is recorded in the
> AUDIT_CONFIG_CHANGE record
> - The value of the "res" field in the CONFIG_CHANGE audit record is corrected
> (1 indicates success, 0 failure)
> - Updated patch 3's commit message to reflect the updated audit record format
> in the examples
> * Patch 4
> - A function comment for audit_seccomp() was added to explain, among other
> things, that event filtering is performed in seccomp_log()
Kees, are you still okay with v3? Also, are you okay with these
patches going in via the audit tree, or would you prefer to take them
via seccomp? I've got a slight preference for the audit tree myself,
but as I said before, as long as it hits Linus' tree I'm happy.
--
paul moore
http://www.paul-moore.com
On Sun, May 6, 2018 at 2:31 PM, Paul Moore <[email protected]> wrote:
> On Thu, May 3, 2018 at 9:08 PM, Tyler Hicks <[email protected]> wrote:
>> Seccomp received improved logging controls in v4.14. Applications can opt into
>> logging of "handled" actions (SECCOMP_RET_TRAP, SECCOMP_RET_TRACE,
>> SECCOMP_RET_ERRNO) using the SECCOMP_FILTER_FLAG_LOG bit when loading filters.
>> They can also debug filter matching with the new SECCOMP_RET_LOG action.
>> Administrators can prevent specific actions from being logged using the
>> kernel.seccomp.actions_logged sysctl.
>>
>> However, one corner case intentionally wasn't addressed in those v4.14 changes.
>> When a process is being inspected by the audit subsystem, seccomp's decision
>> making for logging ignores the new controls and unconditionally logs every
>> action taken except for SECCOMP_RET_ALLOW. This isn't particularly useful since
>> many existing applications don't intend to log handled actions due to them
>> occurring very frequently. This amount of logging fills the audit logs without
>> providing many benefits now that application authors have fine grained controls
>> at their disposal.
>>
>> This patch set aligns the seccomp logging behavior for both audited and
>> non-audited processes. It also emits an audit record, if auditing is enabled,
>> when the kernel.seccomp.actions_logged sysctl is written to so that there's a
>> paper trail when entire actions are quieted.
>>
>> Changes in v3:
>> * Patch 3
>> - Never drop a field when emitting the audit record
>> - Use the value "?" for the actions field when an error occurred while
>> writing to the sysctl
>> - Use the value "?" for the actions and/or old-actions fields when a failure
>> to translate actions to names
>> - Use the value "(none)" for the actions and/or old-actions fields when no
>> actions are specified
>> + This is possible when writing an empty string to the sysctl
>> - Update the commit message to note the new values and give an example of
>> when an empty string is written
>> * Patch 4
>> - Adjust the control flow of seccomp_log() to exit early if nothing should be
>> logged
>>
>> Changes in v2:
>> * Patch 2
>> - New patch, allowing for a configurable separator between action names
>> * Patch 3
>> - The value of the actions field in the audit record now uses a comma instead
>> of a space
>> - The value of the actions field in the audit record is no longer enclosed in
>> quotes
>> - audit_log_start() is called with the current processes' audit_context in
>> audit_seccomp_actions_logged()
>> - audit_seccomp_actions_logged() no longer records the pid, uid, auid, tty,
>> ses, task context, comm, or executable path
>> - The new and old value of seccomp_actions_logged is recorded in the
>> AUDIT_CONFIG_CHANGE record
>> - The value of the "res" field in the CONFIG_CHANGE audit record is corrected
>> (1 indicates success, 0 failure)
>> - Updated patch 3's commit message to reflect the updated audit record format
>> in the examples
>> * Patch 4
>> - A function comment for audit_seccomp() was added to explain, among other
>> things, that event filtering is performed in seccomp_log()
>
> Kees, are you still okay with v3? Also, are you okay with these
> patches going in via the audit tree, or would you prefer to take them
> via seccomp? I've got a slight preference for the audit tree myself,
> but as I said before, as long as it hits Linus' tree I'm happy.
Yup, it looks good. I have no tree preference, so you win! :) Please
consider the whole series:
Acked-by: Kees Cook <[email protected]>
-Kees
--
Kees Cook
Pixel Security
On Sun, May 6, 2018 at 7:36 PM, Kees Cook <[email protected]> wrote:
> On Sun, May 6, 2018 at 2:31 PM, Paul Moore <[email protected]> wrote:
>> On Thu, May 3, 2018 at 9:08 PM, Tyler Hicks <[email protected]> wrote:
>>> Seccomp received improved logging controls in v4.14. Applications can opt into
>>> logging of "handled" actions (SECCOMP_RET_TRAP, SECCOMP_RET_TRACE,
>>> SECCOMP_RET_ERRNO) using the SECCOMP_FILTER_FLAG_LOG bit when loading filters.
>>> They can also debug filter matching with the new SECCOMP_RET_LOG action.
>>> Administrators can prevent specific actions from being logged using the
>>> kernel.seccomp.actions_logged sysctl.
>>>
>>> However, one corner case intentionally wasn't addressed in those v4.14 changes.
>>> When a process is being inspected by the audit subsystem, seccomp's decision
>>> making for logging ignores the new controls and unconditionally logs every
>>> action taken except for SECCOMP_RET_ALLOW. This isn't particularly useful since
>>> many existing applications don't intend to log handled actions due to them
>>> occurring very frequently. This amount of logging fills the audit logs without
>>> providing many benefits now that application authors have fine grained controls
>>> at their disposal.
>>>
>>> This patch set aligns the seccomp logging behavior for both audited and
>>> non-audited processes. It also emits an audit record, if auditing is enabled,
>>> when the kernel.seccomp.actions_logged sysctl is written to so that there's a
>>> paper trail when entire actions are quieted.
>>>
>>> Changes in v3:
>>> * Patch 3
>>> - Never drop a field when emitting the audit record
>>> - Use the value "?" for the actions field when an error occurred while
>>> writing to the sysctl
>>> - Use the value "?" for the actions and/or old-actions fields when a failure
>>> to translate actions to names
>>> - Use the value "(none)" for the actions and/or old-actions fields when no
>>> actions are specified
>>> + This is possible when writing an empty string to the sysctl
>>> - Update the commit message to note the new values and give an example of
>>> when an empty string is written
>>> * Patch 4
>>> - Adjust the control flow of seccomp_log() to exit early if nothing should be
>>> logged
>>>
>>> Changes in v2:
>>> * Patch 2
>>> - New patch, allowing for a configurable separator between action names
>>> * Patch 3
>>> - The value of the actions field in the audit record now uses a comma instead
>>> of a space
>>> - The value of the actions field in the audit record is no longer enclosed in
>>> quotes
>>> - audit_log_start() is called with the current processes' audit_context in
>>> audit_seccomp_actions_logged()
>>> - audit_seccomp_actions_logged() no longer records the pid, uid, auid, tty,
>>> ses, task context, comm, or executable path
>>> - The new and old value of seccomp_actions_logged is recorded in the
>>> AUDIT_CONFIG_CHANGE record
>>> - The value of the "res" field in the CONFIG_CHANGE audit record is corrected
>>> (1 indicates success, 0 failure)
>>> - Updated patch 3's commit message to reflect the updated audit record format
>>> in the examples
>>> * Patch 4
>>> - A function comment for audit_seccomp() was added to explain, among other
>>> things, that event filtering is performed in seccomp_log()
>>
>> Kees, are you still okay with v3? Also, are you okay with these
>> patches going in via the audit tree, or would you prefer to take them
>> via seccomp? I've got a slight preference for the audit tree myself,
>> but as I said before, as long as it hits Linus' tree I'm happy.
>
> Yup, it looks good. I have no tree preference, so you win! :) Please
> consider the whole series:
>
> Acked-by: Kees Cook <[email protected]>
Merged into audit/next, thanks guys.
--
paul moore
http://www.paul-moore.com