|
@@ -42,6 +42,8 @@
|
|
|
* and <dustin.kirkland@us.ibm.com> for LSPP certification compliance.
|
|
|
*/
|
|
|
|
|
|
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
+
|
|
|
#include <linux/init.h>
|
|
|
#include <asm/types.h>
|
|
|
#include <linux/atomic.h>
|
|
@@ -68,6 +70,7 @@
|
|
|
#include <linux/capability.h>
|
|
|
#include <linux/fs_struct.h>
|
|
|
#include <linux/compat.h>
|
|
|
+#include <linux/ctype.h>
|
|
|
|
|
|
#include "audit.h"
|
|
|
|
|
@@ -79,6 +82,9 @@
|
|
|
/* no execve audit message should be longer than this (userspace limits) */
|
|
|
#define MAX_EXECVE_AUDIT_LEN 7500
|
|
|
|
|
|
+/* max length to print of cmdline/proctitle value during audit */
|
|
|
+#define MAX_PROCTITLE_AUDIT_LEN 128
|
|
|
+
|
|
|
/* number of audit rules */
|
|
|
int audit_n_rules;
|
|
|
|
|
@@ -451,15 +457,17 @@ static int audit_filter_rules(struct task_struct *tsk,
|
|
|
struct audit_field *f = &rule->fields[i];
|
|
|
struct audit_names *n;
|
|
|
int result = 0;
|
|
|
+ pid_t pid;
|
|
|
|
|
|
switch (f->type) {
|
|
|
case AUDIT_PID:
|
|
|
- result = audit_comparator(tsk->pid, f->op, f->val);
|
|
|
+ pid = task_pid_nr(tsk);
|
|
|
+ result = audit_comparator(pid, f->op, f->val);
|
|
|
break;
|
|
|
case AUDIT_PPID:
|
|
|
if (ctx) {
|
|
|
if (!ctx->ppid)
|
|
|
- ctx->ppid = sys_getppid();
|
|
|
+ ctx->ppid = task_ppid_nr(tsk);
|
|
|
result = audit_comparator(ctx->ppid, f->op, f->val);
|
|
|
}
|
|
|
break;
|
|
@@ -805,7 +813,8 @@ void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
-static inline struct audit_context *audit_get_context(struct task_struct *tsk,
|
|
|
+/* Transfer the audit context pointer to the caller, clearing it in the tsk's struct */
|
|
|
+static inline struct audit_context *audit_take_context(struct task_struct *tsk,
|
|
|
int return_valid,
|
|
|
long return_code)
|
|
|
{
|
|
@@ -842,6 +851,13 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
|
|
|
return context;
|
|
|
}
|
|
|
|
|
|
+static inline void audit_proctitle_free(struct audit_context *context)
|
|
|
+{
|
|
|
+ kfree(context->proctitle.value);
|
|
|
+ context->proctitle.value = NULL;
|
|
|
+ context->proctitle.len = 0;
|
|
|
+}
|
|
|
+
|
|
|
static inline void audit_free_names(struct audit_context *context)
|
|
|
{
|
|
|
struct audit_names *n, *next;
|
|
@@ -850,16 +866,15 @@ static inline void audit_free_names(struct audit_context *context)
|
|
|
if (context->put_count + context->ino_count != context->name_count) {
|
|
|
int i = 0;
|
|
|
|
|
|
- printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
|
|
|
- " name_count=%d put_count=%d"
|
|
|
- " ino_count=%d [NOT freeing]\n",
|
|
|
- __FILE__, __LINE__,
|
|
|
+ pr_err("%s:%d(:%d): major=%d in_syscall=%d"
|
|
|
+ " name_count=%d put_count=%d ino_count=%d"
|
|
|
+ " [NOT freeing]\n", __FILE__, __LINE__,
|
|
|
context->serial, context->major, context->in_syscall,
|
|
|
context->name_count, context->put_count,
|
|
|
context->ino_count);
|
|
|
list_for_each_entry(n, &context->names_list, list) {
|
|
|
- printk(KERN_ERR "names[%d] = %p = %s\n", i++,
|
|
|
- n->name, n->name->name ?: "(null)");
|
|
|
+ pr_err("names[%d] = %p = %s\n", i++, n->name,
|
|
|
+ n->name->name ?: "(null)");
|
|
|
}
|
|
|
dump_stack();
|
|
|
return;
|
|
@@ -955,6 +970,7 @@ static inline void audit_free_context(struct audit_context *context)
|
|
|
audit_free_aux(context);
|
|
|
kfree(context->filterkey);
|
|
|
kfree(context->sockaddr);
|
|
|
+ audit_proctitle_free(context);
|
|
|
kfree(context);
|
|
|
}
|
|
|
|
|
@@ -1157,7 +1173,7 @@ static void audit_log_execve_info(struct audit_context *context,
|
|
|
*/
|
|
|
buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
|
|
|
if (!buf) {
|
|
|
- audit_panic("out of memory for argv string\n");
|
|
|
+ audit_panic("out of memory for argv string");
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1271,6 +1287,59 @@ static void show_special(struct audit_context *context, int *call_panic)
|
|
|
audit_log_end(ab);
|
|
|
}
|
|
|
|
|
|
+static inline int audit_proctitle_rtrim(char *proctitle, int len)
|
|
|
+{
|
|
|
+ char *end = proctitle + len - 1;
|
|
|
+ while (end > proctitle && !isprint(*end))
|
|
|
+ end--;
|
|
|
+
|
|
|
+ /* catch the case where proctitle is only 1 non-print character */
|
|
|
+ len = end - proctitle + 1;
|
|
|
+ len -= isprint(proctitle[len-1]) == 0;
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+static void audit_log_proctitle(struct task_struct *tsk,
|
|
|
+ struct audit_context *context)
|
|
|
+{
|
|
|
+ int res;
|
|
|
+ char *buf;
|
|
|
+ char *msg = "(null)";
|
|
|
+ int len = strlen(msg);
|
|
|
+ struct audit_buffer *ab;
|
|
|
+
|
|
|
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_PROCTITLE);
|
|
|
+ if (!ab)
|
|
|
+ return; /* audit_panic or being filtered */
|
|
|
+
|
|
|
+ audit_log_format(ab, "proctitle=");
|
|
|
+
|
|
|
+ /* Not cached */
|
|
|
+ if (!context->proctitle.value) {
|
|
|
+ buf = kmalloc(MAX_PROCTITLE_AUDIT_LEN, GFP_KERNEL);
|
|
|
+ if (!buf)
|
|
|
+ goto out;
|
|
|
+ /* Historically called this from procfs naming */
|
|
|
+ res = get_cmdline(tsk, buf, MAX_PROCTITLE_AUDIT_LEN);
|
|
|
+ if (res == 0) {
|
|
|
+ kfree(buf);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ res = audit_proctitle_rtrim(buf, res);
|
|
|
+ if (res == 0) {
|
|
|
+ kfree(buf);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ context->proctitle.value = buf;
|
|
|
+ context->proctitle.len = res;
|
|
|
+ }
|
|
|
+ msg = context->proctitle.value;
|
|
|
+ len = context->proctitle.len;
|
|
|
+out:
|
|
|
+ audit_log_n_untrustedstring(ab, msg, len);
|
|
|
+ audit_log_end(ab);
|
|
|
+}
|
|
|
+
|
|
|
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
|
|
|
{
|
|
|
int i, call_panic = 0;
|
|
@@ -1388,6 +1457,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
|
|
|
audit_log_name(context, n, NULL, i++, &call_panic);
|
|
|
}
|
|
|
|
|
|
+ audit_log_proctitle(tsk, context);
|
|
|
+
|
|
|
/* Send end of event record to help user space know we are finished */
|
|
|
ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
|
|
|
if (ab)
|
|
@@ -1406,7 +1477,7 @@ void __audit_free(struct task_struct *tsk)
|
|
|
{
|
|
|
struct audit_context *context;
|
|
|
|
|
|
- context = audit_get_context(tsk, 0, 0);
|
|
|
+ context = audit_take_context(tsk, 0, 0);
|
|
|
if (!context)
|
|
|
return;
|
|
|
|
|
@@ -1500,7 +1571,7 @@ void __audit_syscall_exit(int success, long return_code)
|
|
|
else
|
|
|
success = AUDITSC_FAILURE;
|
|
|
|
|
|
- context = audit_get_context(tsk, success, return_code);
|
|
|
+ context = audit_take_context(tsk, success, return_code);
|
|
|
if (!context)
|
|
|
return;
|
|
|
|
|
@@ -1550,7 +1621,7 @@ static inline void handle_one(const struct inode *inode)
|
|
|
if (likely(put_tree_ref(context, chunk)))
|
|
|
return;
|
|
|
if (unlikely(!grow_tree_refs(context))) {
|
|
|
- printk(KERN_WARNING "out of memory, audit has lost a tree reference\n");
|
|
|
+ pr_warn("out of memory, audit has lost a tree reference\n");
|
|
|
audit_set_auditable(context);
|
|
|
audit_put_chunk(chunk);
|
|
|
unroll_tree_refs(context, p, count);
|
|
@@ -1609,8 +1680,7 @@ retry:
|
|
|
goto retry;
|
|
|
}
|
|
|
/* too bad */
|
|
|
- printk(KERN_WARNING
|
|
|
- "out of memory, audit has lost a tree reference\n");
|
|
|
+ pr_warn("out of memory, audit has lost a tree reference\n");
|
|
|
unroll_tree_refs(context, p, count);
|
|
|
audit_set_auditable(context);
|
|
|
return;
|
|
@@ -1682,7 +1752,7 @@ void __audit_getname(struct filename *name)
|
|
|
|
|
|
if (!context->in_syscall) {
|
|
|
#if AUDIT_DEBUG == 2
|
|
|
- printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n",
|
|
|
+ pr_err("%s:%d(:%d): ignoring getname(%p)\n",
|
|
|
__FILE__, __LINE__, context->serial, name);
|
|
|
dump_stack();
|
|
|
#endif
|
|
@@ -1721,15 +1791,15 @@ void audit_putname(struct filename *name)
|
|
|
BUG_ON(!context);
|
|
|
if (!name->aname || !context->in_syscall) {
|
|
|
#if AUDIT_DEBUG == 2
|
|
|
- printk(KERN_ERR "%s:%d(:%d): final_putname(%p)\n",
|
|
|
+ pr_err("%s:%d(:%d): final_putname(%p)\n",
|
|
|
__FILE__, __LINE__, context->serial, name);
|
|
|
if (context->name_count) {
|
|
|
struct audit_names *n;
|
|
|
int i = 0;
|
|
|
|
|
|
list_for_each_entry(n, &context->names_list, list)
|
|
|
- printk(KERN_ERR "name[%d] = %p = %s\n", i++,
|
|
|
- n->name, n->name->name ?: "(null)");
|
|
|
+ pr_err("name[%d] = %p = %s\n", i++, n->name,
|
|
|
+ n->name->name ?: "(null)");
|
|
|
}
|
|
|
#endif
|
|
|
final_putname(name);
|
|
@@ -1738,9 +1808,8 @@ void audit_putname(struct filename *name)
|
|
|
else {
|
|
|
++context->put_count;
|
|
|
if (context->put_count > context->name_count) {
|
|
|
- printk(KERN_ERR "%s:%d(:%d): major=%d"
|
|
|
- " in_syscall=%d putname(%p) name_count=%d"
|
|
|
- " put_count=%d\n",
|
|
|
+ pr_err("%s:%d(:%d): major=%d in_syscall=%d putname(%p)"
|
|
|
+ " name_count=%d put_count=%d\n",
|
|
|
__FILE__, __LINE__,
|
|
|
context->serial, context->major,
|
|
|
context->in_syscall, name->name,
|
|
@@ -1981,12 +2050,10 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
|
|
|
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
|
|
|
if (!ab)
|
|
|
return;
|
|
|
- audit_log_format(ab, "pid=%d uid=%u"
|
|
|
- " old-auid=%u new-auid=%u old-ses=%u new-ses=%u"
|
|
|
- " res=%d",
|
|
|
- current->pid, uid,
|
|
|
- oldloginuid, loginuid, oldsessionid, sessionid,
|
|
|
- !rc);
|
|
|
+ audit_log_format(ab, "pid=%d uid=%u", task_pid_nr(current), uid);
|
|
|
+ audit_log_task_context(ab);
|
|
|
+ audit_log_format(ab, " old-auid=%u auid=%u old-ses=%u ses=%u res=%d",
|
|
|
+ oldloginuid, loginuid, oldsessionid, sessionid, !rc);
|
|
|
audit_log_end(ab);
|
|
|
}
|
|
|
|
|
@@ -2208,7 +2275,7 @@ void __audit_ptrace(struct task_struct *t)
|
|
|
{
|
|
|
struct audit_context *context = current->audit_context;
|
|
|
|
|
|
- context->target_pid = t->pid;
|
|
|
+ context->target_pid = task_pid_nr(t);
|
|
|
context->target_auid = audit_get_loginuid(t);
|
|
|
context->target_uid = task_uid(t);
|
|
|
context->target_sessionid = audit_get_sessionid(t);
|
|
@@ -2233,7 +2300,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
|
|
|
|
|
|
if (audit_pid && t->tgid == audit_pid) {
|
|
|
if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
|
|
|
- audit_sig_pid = tsk->pid;
|
|
|
+ audit_sig_pid = task_pid_nr(tsk);
|
|
|
if (uid_valid(tsk->loginuid))
|
|
|
audit_sig_uid = tsk->loginuid;
|
|
|
else
|
|
@@ -2247,7 +2314,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
|
|
|
/* optimize the common case by putting first signal recipient directly
|
|
|
* in audit_context */
|
|
|
if (!ctx->target_pid) {
|
|
|
- ctx->target_pid = t->tgid;
|
|
|
+ ctx->target_pid = task_tgid_nr(t);
|
|
|
ctx->target_auid = audit_get_loginuid(t);
|
|
|
ctx->target_uid = t_uid;
|
|
|
ctx->target_sessionid = audit_get_sessionid(t);
|
|
@@ -2268,7 +2335,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
|
|
|
}
|
|
|
BUG_ON(axp->pid_count >= AUDIT_AUX_PIDS);
|
|
|
|
|
|
- axp->target_pid[axp->pid_count] = t->tgid;
|
|
|
+ axp->target_pid[axp->pid_count] = task_tgid_nr(t);
|
|
|
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
|
|
|
axp->target_uid[axp->pid_count] = t_uid;
|
|
|
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
|
|
@@ -2368,7 +2435,7 @@ static void audit_log_task(struct audit_buffer *ab)
|
|
|
from_kgid(&init_user_ns, gid),
|
|
|
sessionid);
|
|
|
audit_log_task_context(ab);
|
|
|
- audit_log_format(ab, " pid=%d comm=", current->pid);
|
|
|
+ audit_log_format(ab, " pid=%d comm=", task_pid_nr(current));
|
|
|
audit_log_untrustedstring(ab, current->comm);
|
|
|
if (mm) {
|
|
|
down_read(&mm->mmap_sem);
|