forked from Minki/linux
Merge git://git.infradead.org/users/eparis/audit
Pull audit updates from Eric Paris: "Nothing amazing. Formatting, small bug fixes, couple of fixes where we didn't get records due to some old VFS changes, and a change to how we collect execve info..." Fixed conflict in fs/exec.c as per Eric and linux-next. * git://git.infradead.org/users/eparis/audit: (28 commits) audit: fix type of sessionid in audit_set_loginuid() audit: call audit_bprm() only once to add AUDIT_EXECVE information audit: move audit_aux_data_execve contents into audit_context union audit: remove unused envc member of audit_aux_data_execve audit: Kill the unused struct audit_aux_data_capset audit: do not reject all AUDIT_INODE filter types audit: suppress stock memalloc failure warnings since already managed audit: log the audit_names record type audit: add child record before the create to handle case where create fails audit: use given values in tty_audit enable api audit: use nlmsg_len() to get message payload length audit: use memset instead of trying to initialize field by field audit: fix info leak in AUDIT_GET requests audit: update AUDIT_INODE filter rule to comparator function audit: audit feature to set loginuid immutable audit: audit feature to only allow unsetting the loginuid audit: allow unsetting the loginuid (with priv) audit: remove CONFIG_AUDIT_LOGINUID_IMMUTABLE audit: loginuid functions coding style selinux: apply selinux checks on new audit message types ...
This commit is contained in:
commit
3eaded86ac
@ -1380,10 +1380,6 @@ int search_binary_handler(struct linux_binprm *bprm)
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = audit_bprm(bprm);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = -ENOENT;
|
||||
retry:
|
||||
read_lock(&binfmt_lock);
|
||||
@ -1431,6 +1427,7 @@ static int exec_binprm(struct linux_binprm *bprm)
|
||||
|
||||
ret = search_binary_handler(bprm);
|
||||
if (ret >= 0) {
|
||||
audit_bprm(bprm);
|
||||
trace_sched_process_exec(current, old_pid, bprm);
|
||||
ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
|
||||
current->did_exec = 1;
|
||||
|
@ -2435,6 +2435,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
|
||||
*/
|
||||
static inline int may_create(struct inode *dir, struct dentry *child)
|
||||
{
|
||||
audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
|
||||
if (child->d_inode)
|
||||
return -EEXIST;
|
||||
if (IS_DEADDIR(dir))
|
||||
|
@ -1151,10 +1151,16 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
|
||||
goto out_free_page;
|
||||
|
||||
}
|
||||
kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
|
||||
if (!uid_valid(kloginuid)) {
|
||||
length = -EINVAL;
|
||||
goto out_free_page;
|
||||
|
||||
/* is userspace tring to explicitly UNSET the loginuid? */
|
||||
if (loginuid == AUDIT_UID_UNSET) {
|
||||
kloginuid = INVALID_UID;
|
||||
} else {
|
||||
kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
|
||||
if (!uid_valid(kloginuid)) {
|
||||
length = -EINVAL;
|
||||
goto out_free_page;
|
||||
}
|
||||
}
|
||||
|
||||
length = audit_set_loginuid(kloginuid);
|
||||
|
@ -73,6 +73,8 @@ struct audit_field {
|
||||
void *lsm_rule;
|
||||
};
|
||||
|
||||
extern int is_audit_feature_set(int which);
|
||||
|
||||
extern int __init audit_register_class(int class, unsigned *list);
|
||||
extern int audit_classify_syscall(int abi, unsigned syscall);
|
||||
extern int audit_classify_arch(int arch);
|
||||
@ -207,7 +209,7 @@ static inline int audit_get_sessionid(struct task_struct *tsk)
|
||||
|
||||
extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
|
||||
extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
|
||||
extern int __audit_bprm(struct linux_binprm *bprm);
|
||||
extern void __audit_bprm(struct linux_binprm *bprm);
|
||||
extern int __audit_socketcall(int nargs, unsigned long *args);
|
||||
extern int __audit_sockaddr(int len, void *addr);
|
||||
extern void __audit_fd_pair(int fd1, int fd2);
|
||||
@ -236,11 +238,10 @@ static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid
|
||||
if (unlikely(!audit_dummy_context()))
|
||||
__audit_ipc_set_perm(qbytes, uid, gid, mode);
|
||||
}
|
||||
static inline int audit_bprm(struct linux_binprm *bprm)
|
||||
static inline void audit_bprm(struct linux_binprm *bprm)
|
||||
{
|
||||
if (unlikely(!audit_dummy_context()))
|
||||
return __audit_bprm(bprm);
|
||||
return 0;
|
||||
__audit_bprm(bprm);
|
||||
}
|
||||
static inline int audit_socketcall(int nargs, unsigned long *args)
|
||||
{
|
||||
@ -367,10 +368,8 @@ static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
|
||||
static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid,
|
||||
gid_t gid, umode_t mode)
|
||||
{ }
|
||||
static inline int audit_bprm(struct linux_binprm *bprm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void audit_bprm(struct linux_binprm *bprm)
|
||||
{ }
|
||||
static inline int audit_socketcall(int nargs, unsigned long *args)
|
||||
{
|
||||
return 0;
|
||||
|
@ -68,6 +68,9 @@
|
||||
#define AUDIT_MAKE_EQUIV 1015 /* Append to watched tree */
|
||||
#define AUDIT_TTY_GET 1016 /* Get TTY auditing status */
|
||||
#define AUDIT_TTY_SET 1017 /* Set TTY auditing status */
|
||||
#define AUDIT_SET_FEATURE 1018 /* Turn an audit feature on or off */
|
||||
#define AUDIT_GET_FEATURE 1019 /* Get which features are enabled */
|
||||
#define AUDIT_FEATURE_CHANGE 1020 /* audit log listing feature changes */
|
||||
|
||||
#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */
|
||||
#define AUDIT_USER_AVC 1107 /* We filter this differently */
|
||||
@ -357,6 +360,12 @@ enum {
|
||||
#define AUDIT_PERM_READ 4
|
||||
#define AUDIT_PERM_ATTR 8
|
||||
|
||||
/* MAX_AUDIT_MESSAGE_LENGTH is set in audit:lib/libaudit.h as:
|
||||
* 8970 // PATH_MAX*2+CONTEXT_SIZE*2+11+256+1
|
||||
* max header+body+tailer: 44 + 29 + 32 + 262 + 7 + pad
|
||||
*/
|
||||
#define AUDIT_MESSAGE_TEXT_MAX 8560
|
||||
|
||||
struct audit_status {
|
||||
__u32 mask; /* Bit mask for valid entries */
|
||||
__u32 enabled; /* 1 = enabled, 0 = disabled */
|
||||
@ -368,11 +377,28 @@ struct audit_status {
|
||||
__u32 backlog; /* messages waiting in queue */
|
||||
};
|
||||
|
||||
struct audit_features {
|
||||
#define AUDIT_FEATURE_VERSION 1
|
||||
__u32 vers;
|
||||
__u32 mask; /* which bits we are dealing with */
|
||||
__u32 features; /* which feature to enable/disable */
|
||||
__u32 lock; /* which features to lock */
|
||||
};
|
||||
|
||||
#define AUDIT_FEATURE_ONLY_UNSET_LOGINUID 0
|
||||
#define AUDIT_FEATURE_LOGINUID_IMMUTABLE 1
|
||||
#define AUDIT_LAST_FEATURE AUDIT_FEATURE_LOGINUID_IMMUTABLE
|
||||
|
||||
#define audit_feature_valid(x) ((x) >= 0 && (x) <= AUDIT_LAST_FEATURE)
|
||||
#define AUDIT_FEATURE_TO_MASK(x) (1 << ((x) & 31)) /* mask for __u32 */
|
||||
|
||||
struct audit_tty_status {
|
||||
__u32 enabled; /* 1 = enabled, 0 = disabled */
|
||||
__u32 log_passwd; /* 1 = enabled, 0 = disabled */
|
||||
};
|
||||
|
||||
#define AUDIT_UID_UNSET (unsigned int)-1
|
||||
|
||||
/* audit_rule_data supports filter rules with both integer and string
|
||||
* fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
|
||||
* AUDIT_LIST_RULES requests.
|
||||
|
14
init/Kconfig
14
init/Kconfig
@ -301,20 +301,6 @@ config AUDIT_TREE
|
||||
depends on AUDITSYSCALL
|
||||
select FSNOTIFY
|
||||
|
||||
config AUDIT_LOGINUID_IMMUTABLE
|
||||
bool "Make audit loginuid immutable"
|
||||
depends on AUDIT
|
||||
help
|
||||
The config option toggles if a task setting its loginuid requires
|
||||
CAP_SYS_AUDITCONTROL or if that task should require no special permissions
|
||||
but should instead only allow setting its loginuid if it was never
|
||||
previously set. On systems which use systemd or a similar central
|
||||
process to restart login services this should be set to true. On older
|
||||
systems in which an admin would typically have to directly stop and
|
||||
start processes this should be set to false. Setting this to true allows
|
||||
one to drop potentially dangerous capabilites from the login tasks,
|
||||
but may not be backwards compatible with older init systems.
|
||||
|
||||
source "kernel/irq/Kconfig"
|
||||
source "kernel/time/Kconfig"
|
||||
|
||||
|
153
kernel/audit.c
153
kernel/audit.c
@ -60,7 +60,6 @@
|
||||
#ifdef CONFIG_SECURITY
|
||||
#include <linux/security.h>
|
||||
#endif
|
||||
#include <net/netlink.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
@ -140,6 +139,17 @@ static struct task_struct *kauditd_task;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
|
||||
|
||||
static struct audit_features af = {.vers = AUDIT_FEATURE_VERSION,
|
||||
.mask = -1,
|
||||
.features = 0,
|
||||
.lock = 0,};
|
||||
|
||||
static char *audit_feature_names[2] = {
|
||||
"only_unset_loginuid",
|
||||
"loginuid_immutable",
|
||||
};
|
||||
|
||||
|
||||
/* Serialize requests from userspace. */
|
||||
DEFINE_MUTEX(audit_cmd_mutex);
|
||||
|
||||
@ -584,6 +594,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
|
||||
return -EOPNOTSUPP;
|
||||
case AUDIT_GET:
|
||||
case AUDIT_SET:
|
||||
case AUDIT_GET_FEATURE:
|
||||
case AUDIT_SET_FEATURE:
|
||||
case AUDIT_LIST_RULES:
|
||||
case AUDIT_ADD_RULE:
|
||||
case AUDIT_DEL_RULE:
|
||||
@ -613,7 +625,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
|
||||
int rc = 0;
|
||||
uid_t uid = from_kuid(&init_user_ns, current_uid());
|
||||
|
||||
if (!audit_enabled) {
|
||||
if (!audit_enabled && msg_type != AUDIT_USER_AVC) {
|
||||
*ab = NULL;
|
||||
return rc;
|
||||
}
|
||||
@ -628,6 +640,94 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int is_audit_feature_set(int i)
|
||||
{
|
||||
return af.features & AUDIT_FEATURE_TO_MASK(i);
|
||||
}
|
||||
|
||||
|
||||
static int audit_get_feature(struct sk_buff *skb)
|
||||
{
|
||||
u32 seq;
|
||||
|
||||
seq = nlmsg_hdr(skb)->nlmsg_seq;
|
||||
|
||||
audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
|
||||
&af, sizeof(af));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature,
|
||||
u32 old_lock, u32 new_lock, int res)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
|
||||
audit_log_format(ab, "feature=%s new=%d old=%d old_lock=%d new_lock=%d res=%d",
|
||||
audit_feature_names[which], !!old_feature, !!new_feature,
|
||||
!!old_lock, !!new_lock, res);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
static int audit_set_feature(struct sk_buff *skb)
|
||||
{
|
||||
struct audit_features *uaf;
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > sizeof(audit_feature_names)/sizeof(audit_feature_names[0]));
|
||||
uaf = nlmsg_data(nlmsg_hdr(skb));
|
||||
|
||||
/* if there is ever a version 2 we should handle that here */
|
||||
|
||||
for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
|
||||
u32 feature = AUDIT_FEATURE_TO_MASK(i);
|
||||
u32 old_feature, new_feature, old_lock, new_lock;
|
||||
|
||||
/* if we are not changing this feature, move along */
|
||||
if (!(feature & uaf->mask))
|
||||
continue;
|
||||
|
||||
old_feature = af.features & feature;
|
||||
new_feature = uaf->features & feature;
|
||||
new_lock = (uaf->lock | af.lock) & feature;
|
||||
old_lock = af.lock & feature;
|
||||
|
||||
/* are we changing a locked feature? */
|
||||
if ((af.lock & feature) && (new_feature != old_feature)) {
|
||||
audit_log_feature_change(i, old_feature, new_feature,
|
||||
old_lock, new_lock, 0);
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
/* nothing invalid, do the changes */
|
||||
for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
|
||||
u32 feature = AUDIT_FEATURE_TO_MASK(i);
|
||||
u32 old_feature, new_feature, old_lock, new_lock;
|
||||
|
||||
/* if we are not changing this feature, move along */
|
||||
if (!(feature & uaf->mask))
|
||||
continue;
|
||||
|
||||
old_feature = af.features & feature;
|
||||
new_feature = uaf->features & feature;
|
||||
old_lock = af.lock & feature;
|
||||
new_lock = (uaf->lock | af.lock) & feature;
|
||||
|
||||
if (new_feature != old_feature)
|
||||
audit_log_feature_change(i, old_feature, new_feature,
|
||||
old_lock, new_lock, 1);
|
||||
|
||||
if (new_feature)
|
||||
af.features |= feature;
|
||||
else
|
||||
af.features &= ~feature;
|
||||
af.lock |= new_lock;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
{
|
||||
u32 seq;
|
||||
@ -659,6 +759,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
|
||||
switch (msg_type) {
|
||||
case AUDIT_GET:
|
||||
memset(&status_set, 0, sizeof(status_set));
|
||||
status_set.enabled = audit_enabled;
|
||||
status_set.failure = audit_failure;
|
||||
status_set.pid = audit_pid;
|
||||
@ -670,7 +771,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
&status_set, sizeof(status_set));
|
||||
break;
|
||||
case AUDIT_SET:
|
||||
if (nlh->nlmsg_len < sizeof(struct audit_status))
|
||||
if (nlmsg_len(nlh) < sizeof(struct audit_status))
|
||||
return -EINVAL;
|
||||
status_get = (struct audit_status *)data;
|
||||
if (status_get->mask & AUDIT_STATUS_ENABLED) {
|
||||
@ -699,6 +800,16 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
|
||||
err = audit_set_backlog_limit(status_get->backlog_limit);
|
||||
break;
|
||||
case AUDIT_GET_FEATURE:
|
||||
err = audit_get_feature(skb);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case AUDIT_SET_FEATURE:
|
||||
err = audit_set_feature(skb);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case AUDIT_USER:
|
||||
case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
|
||||
case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
|
||||
@ -715,7 +826,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
}
|
||||
audit_log_common_recv_msg(&ab, msg_type);
|
||||
if (msg_type != AUDIT_USER_TTY)
|
||||
audit_log_format(ab, " msg='%.1024s'",
|
||||
audit_log_format(ab, " msg='%.*s'",
|
||||
AUDIT_MESSAGE_TEXT_MAX,
|
||||
(char *)data);
|
||||
else {
|
||||
int size;
|
||||
@ -818,7 +930,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
spin_lock(&tsk->sighand->siglock);
|
||||
s.enabled = tsk->signal->audit_tty != 0;
|
||||
s.enabled = tsk->signal->audit_tty;
|
||||
s.log_passwd = tsk->signal->audit_tty_log_passwd;
|
||||
spin_unlock(&tsk->sighand->siglock);
|
||||
|
||||
@ -832,7 +944,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
/* guard against past and future API changes */
|
||||
memcpy(&s, data, min(sizeof(s), (size_t)nlh->nlmsg_len));
|
||||
memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
|
||||
if ((s.enabled != 0 && s.enabled != 1) ||
|
||||
(s.log_passwd != 0 && s.log_passwd != 1))
|
||||
return -EINVAL;
|
||||
@ -1067,13 +1179,6 @@ static void wait_for_auditd(unsigned long sleep_time)
|
||||
remove_wait_queue(&audit_backlog_wait, &wait);
|
||||
}
|
||||
|
||||
/* Obtain an audit buffer. This routine does locking to obtain the
|
||||
* audit buffer, but then no locking is required for calls to
|
||||
* audit_log_*format. If the tsk is a task that is currently in a
|
||||
* syscall, then the syscall is marked as auditable and an audit record
|
||||
* will be written at syscall exit. If there is no associated task, tsk
|
||||
* should be NULL. */
|
||||
|
||||
/**
|
||||
* audit_log_start - obtain an audit buffer
|
||||
* @ctx: audit_context (may be NULL)
|
||||
@ -1389,7 +1494,7 @@ void audit_log_session_info(struct audit_buffer *ab)
|
||||
u32 sessionid = audit_get_sessionid(current);
|
||||
uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
|
||||
|
||||
audit_log_format(ab, " auid=%u ses=%u\n", auid, sessionid);
|
||||
audit_log_format(ab, " auid=%u ses=%u", auid, sessionid);
|
||||
}
|
||||
|
||||
void audit_log_key(struct audit_buffer *ab, char *key)
|
||||
@ -1536,6 +1641,26 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
|
||||
}
|
||||
}
|
||||
|
||||
/* log the audit_names record type */
|
||||
audit_log_format(ab, " nametype=");
|
||||
switch(n->type) {
|
||||
case AUDIT_TYPE_NORMAL:
|
||||
audit_log_format(ab, "NORMAL");
|
||||
break;
|
||||
case AUDIT_TYPE_PARENT:
|
||||
audit_log_format(ab, "PARENT");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_DELETE:
|
||||
audit_log_format(ab, "DELETE");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_CREATE:
|
||||
audit_log_format(ab, "CREATE");
|
||||
break;
|
||||
default:
|
||||
audit_log_format(ab, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
|
||||
audit_log_fcaps(ab, n);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
@ -197,6 +197,9 @@ struct audit_context {
|
||||
int fd;
|
||||
int flags;
|
||||
} mmap;
|
||||
struct {
|
||||
int argc;
|
||||
} execve;
|
||||
};
|
||||
int fds[2];
|
||||
|
||||
|
@ -343,6 +343,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
|
||||
case AUDIT_DEVMINOR:
|
||||
case AUDIT_EXIT:
|
||||
case AUDIT_SUCCESS:
|
||||
case AUDIT_INODE:
|
||||
/* bit ops are only useful on syscall args */
|
||||
if (f->op == Audit_bitmask || f->op == Audit_bittest)
|
||||
return -EINVAL;
|
||||
@ -423,7 +424,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
|
||||
f->lsm_rule = NULL;
|
||||
|
||||
/* Support legacy tests for a valid loginuid */
|
||||
if ((f->type == AUDIT_LOGINUID) && (f->val == ~0U)) {
|
||||
if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
|
||||
f->type = AUDIT_LOGINUID_SET;
|
||||
f->val = 0;
|
||||
}
|
||||
|
133
kernel/auditsc.c
133
kernel/auditsc.c
@ -95,13 +95,6 @@ struct audit_aux_data {
|
||||
/* Number of target pids per aux struct. */
|
||||
#define AUDIT_AUX_PIDS 16
|
||||
|
||||
struct audit_aux_data_execve {
|
||||
struct audit_aux_data d;
|
||||
int argc;
|
||||
int envc;
|
||||
struct mm_struct *mm;
|
||||
};
|
||||
|
||||
struct audit_aux_data_pids {
|
||||
struct audit_aux_data d;
|
||||
pid_t target_pid[AUDIT_AUX_PIDS];
|
||||
@ -121,12 +114,6 @@ struct audit_aux_data_bprm_fcaps {
|
||||
struct audit_cap_data new_pcap;
|
||||
};
|
||||
|
||||
struct audit_aux_data_capset {
|
||||
struct audit_aux_data d;
|
||||
pid_t pid;
|
||||
struct audit_cap_data cap;
|
||||
};
|
||||
|
||||
struct audit_tree_refs {
|
||||
struct audit_tree_refs *next;
|
||||
struct audit_chunk *c[31];
|
||||
@ -566,7 +553,7 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
break;
|
||||
case AUDIT_INODE:
|
||||
if (name)
|
||||
result = (name->ino == f->val);
|
||||
result = audit_comparator(name->ino, f->op, f->val);
|
||||
else if (ctx) {
|
||||
list_for_each_entry(n, &ctx->names_list, list) {
|
||||
if (audit_comparator(n->ino, f->op, f->val)) {
|
||||
@ -943,8 +930,10 @@ int audit_alloc(struct task_struct *tsk)
|
||||
return 0; /* Return if not auditing. */
|
||||
|
||||
state = audit_filter_task(tsk, &key);
|
||||
if (state == AUDIT_DISABLED)
|
||||
if (state == AUDIT_DISABLED) {
|
||||
clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(context = audit_alloc_context(state))) {
|
||||
kfree(key);
|
||||
@ -1149,20 +1138,16 @@ static int audit_log_single_execve_arg(struct audit_context *context,
|
||||
}
|
||||
|
||||
static void audit_log_execve_info(struct audit_context *context,
|
||||
struct audit_buffer **ab,
|
||||
struct audit_aux_data_execve *axi)
|
||||
struct audit_buffer **ab)
|
||||
{
|
||||
int i, len;
|
||||
size_t len_sent = 0;
|
||||
const char __user *p;
|
||||
char *buf;
|
||||
|
||||
if (axi->mm != current->mm)
|
||||
return; /* execve failed, no additional info */
|
||||
p = (const char __user *)current->mm->arg_start;
|
||||
|
||||
p = (const char __user *)axi->mm->arg_start;
|
||||
|
||||
audit_log_format(*ab, "argc=%d", axi->argc);
|
||||
audit_log_format(*ab, "argc=%d", context->execve.argc);
|
||||
|
||||
/*
|
||||
* we need some kernel buffer to hold the userspace args. Just
|
||||
@ -1176,7 +1161,7 @@ static void audit_log_execve_info(struct audit_context *context,
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < axi->argc; i++) {
|
||||
for (i = 0; i < context->execve.argc; i++) {
|
||||
len = audit_log_single_execve_arg(context, ab, i,
|
||||
&len_sent, p, buf);
|
||||
if (len <= 0)
|
||||
@ -1279,6 +1264,9 @@ static void show_special(struct audit_context *context, int *call_panic)
|
||||
audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
|
||||
context->mmap.flags);
|
||||
break; }
|
||||
case AUDIT_EXECVE: {
|
||||
audit_log_execve_info(context, &ab);
|
||||
break; }
|
||||
}
|
||||
audit_log_end(ab);
|
||||
}
|
||||
@ -1325,11 +1313,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
|
||||
|
||||
switch (aux->type) {
|
||||
|
||||
case AUDIT_EXECVE: {
|
||||
struct audit_aux_data_execve *axi = (void *)aux;
|
||||
audit_log_execve_info(context, &ab, axi);
|
||||
break; }
|
||||
|
||||
case AUDIT_BPRM_FCAPS: {
|
||||
struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
|
||||
audit_log_format(ab, "fver=%x", axs->fcap_ver);
|
||||
@ -1964,6 +1947,43 @@ int auditsc_get_stamp(struct audit_context *ctx,
|
||||
/* global counter which is incremented every time something logs in */
|
||||
static atomic_t session_id = ATOMIC_INIT(0);
|
||||
|
||||
static int audit_set_loginuid_perm(kuid_t loginuid)
|
||||
{
|
||||
/* if we are unset, we don't need privs */
|
||||
if (!audit_loginuid_set(current))
|
||||
return 0;
|
||||
/* if AUDIT_FEATURE_LOGINUID_IMMUTABLE means never ever allow a change*/
|
||||
if (is_audit_feature_set(AUDIT_FEATURE_LOGINUID_IMMUTABLE))
|
||||
return -EPERM;
|
||||
/* it is set, you need permission */
|
||||
if (!capable(CAP_AUDIT_CONTROL))
|
||||
return -EPERM;
|
||||
/* reject if this is not an unset and we don't allow that */
|
||||
if (is_audit_feature_set(AUDIT_FEATURE_ONLY_UNSET_LOGINUID) && uid_valid(loginuid))
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
|
||||
unsigned int oldsessionid, unsigned int sessionid,
|
||||
int rc)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
uid_t uid, ologinuid, nloginuid;
|
||||
|
||||
uid = from_kuid(&init_user_ns, task_uid(current));
|
||||
ologinuid = from_kuid(&init_user_ns, koldloginuid);
|
||||
nloginuid = from_kuid(&init_user_ns, 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, ologinuid,
|
||||
nloginuid, oldsessionid, sessionid, !rc);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_set_loginuid - set current task's audit_context loginuid
|
||||
* @loginuid: loginuid value
|
||||
@ -1975,37 +1995,26 @@ static atomic_t session_id = ATOMIC_INIT(0);
|
||||
int audit_set_loginuid(kuid_t loginuid)
|
||||
{
|
||||
struct task_struct *task = current;
|
||||
struct audit_context *context = task->audit_context;
|
||||
unsigned int sessionid;
|
||||
unsigned int oldsessionid, sessionid = (unsigned int)-1;
|
||||
kuid_t oldloginuid;
|
||||
int rc;
|
||||
|
||||
#ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
|
||||
if (audit_loginuid_set(task))
|
||||
return -EPERM;
|
||||
#else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
|
||||
if (!capable(CAP_AUDIT_CONTROL))
|
||||
return -EPERM;
|
||||
#endif /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
|
||||
oldloginuid = audit_get_loginuid(current);
|
||||
oldsessionid = audit_get_sessionid(current);
|
||||
|
||||
sessionid = atomic_inc_return(&session_id);
|
||||
if (context && context->in_syscall) {
|
||||
struct audit_buffer *ab;
|
||||
rc = audit_set_loginuid_perm(loginuid);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* are we setting or clearing? */
|
||||
if (uid_valid(loginuid))
|
||||
sessionid = atomic_inc_return(&session_id);
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
|
||||
if (ab) {
|
||||
audit_log_format(ab, "login pid=%d uid=%u "
|
||||
"old auid=%u new auid=%u"
|
||||
" old ses=%u new ses=%u",
|
||||
task->pid,
|
||||
from_kuid(&init_user_ns, task_uid(task)),
|
||||
from_kuid(&init_user_ns, task->loginuid),
|
||||
from_kuid(&init_user_ns, loginuid),
|
||||
task->sessionid, sessionid);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
}
|
||||
task->sessionid = sessionid;
|
||||
task->loginuid = loginuid;
|
||||
return 0;
|
||||
out:
|
||||
audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2126,22 +2135,12 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mo
|
||||
context->ipc.has_perm = 1;
|
||||
}
|
||||
|
||||
int __audit_bprm(struct linux_binprm *bprm)
|
||||
void __audit_bprm(struct linux_binprm *bprm)
|
||||
{
|
||||
struct audit_aux_data_execve *ax;
|
||||
struct audit_context *context = current->audit_context;
|
||||
|
||||
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
|
||||
if (!ax)
|
||||
return -ENOMEM;
|
||||
|
||||
ax->argc = bprm->argc;
|
||||
ax->envc = bprm->envc;
|
||||
ax->mm = bprm->mm;
|
||||
ax->d.type = AUDIT_EXECVE;
|
||||
ax->d.next = context->aux;
|
||||
context->aux = (void *)ax;
|
||||
return 0;
|
||||
context->type = AUDIT_EXECVE;
|
||||
context->execve.argc = bprm->argc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -397,7 +397,8 @@ void common_lsm_audit(struct common_audit_data *a,
|
||||
if (a == NULL)
|
||||
return;
|
||||
/* we use GFP_ATOMIC so we won't sleep */
|
||||
ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
|
||||
ab = audit_log_start(current->audit_context, GFP_ATOMIC | __GFP_NOWARN,
|
||||
AUDIT_AVC);
|
||||
|
||||
if (ab == NULL)
|
||||
return;
|
||||
|
@ -116,6 +116,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
|
||||
{ AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
|
||||
{ AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
|
||||
{ AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT },
|
||||
{ AUDIT_GET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_READ },
|
||||
{ AUDIT_SET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user