forked from Minki/linux
audit/stable-5.1 PR 20190305
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAlx+8ZgUHHBhdWxAcGF1 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXOlDhAAiGlirQ9syyG2fYzaARZZ2QoU/GGD PSAeiNmP3jvJzXArCvugRCw+YSNDdQOBM3SrLQC+cM0MAIDRYXN0NdcrsbTchlMA 51Fx1egZ9Fyj+Ehgida3muh2lRUy7DQwMCL6tAVqwz7vYkSTGDUf+MlYqOqXDka5 74pEExOS3Jdi7560BsE8b6QoW9JIJqEJnirXGkG9o2qC0oFHCR6PKxIyQ7TJrLR1 F23aFTqLTH1nbPUQjnox2PTf13iQVh4j2gwzd+9c9KBfxoGSge3dmxId7BJHy2aG M27fPdCYTNZAGWpPVujsCPAh1WPQ9NQqg3mA9+g14PEbiLqPcqU+kWmnDU7T7bEw Qx0kt6Y8GiknwCqq8pDbKYclgRmOjSGdfutzd0z8uDpbaeunS4/NqnDb/FUaDVcr jA4d6ep7qEgHpYbL8KgOeZCexfaTfz6mcwRWNq3Uu9cLZbZqSSQ7PXolMADHvoRs LS7VH2jcP7q4p4GWmdfjv67xyUUo9HG5HHX74h5pLfQSYXiBWo4ht0UOAzX/6EcE CJNHAFHv+OanI5Rg/6JQ8b3/bJYxzAJVyLZpCuMtlKk6lYBGNeADk9BezEDIYsm8 tSe4/GqqyR9+Qz8rSdpAZ0KKkfqS535IcHUPUJau7Bzg1xqSEP5gzZN6QsjdXg0+ 5wFFfdFICTfJFXo= =57/1 -----END PGP SIGNATURE----- Merge tag 'audit-pr-20190305' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit Pull audit updates from Paul Moore: "A lucky 13 audit patches for v5.1. Despite the rather large diffstat, most of the changes are from two bug fix patches that move code from one Kconfig option to another. Beyond that bit of churn, the remaining changes are largely cleanups and bug-fixes as we slowly march towards container auditing. It isn't all boring though, we do have a couple of new things: file capabilities v3 support, and expanded support for filtering on filesystems to solve problems with remote filesystems. All changes pass the audit-testsuite. Please merge for v5.1" * tag 'audit-pr-20190305' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit: audit: mark expected switch fall-through audit: hide auditsc_get_stamp and audit_serial prototypes audit: join tty records to their syscall audit: remove audit_context when CONFIG_ AUDIT and not AUDITSYSCALL audit: remove unused actx param from audit_rule_match audit: ignore fcaps on umount audit: clean up AUDITSYSCALL prototypes and stubs audit: more filter PATH records keyed on filesystem magic audit: add support for fcaps v3 audit: move loginuid and sessionid from CONFIG_AUDITSYSCALL to CONFIG_AUDIT audit: add syscall information to CONFIG_CHANGE records audit: hand taken context to audit_kill_trees for syscall logging audit: give a clue what CONFIG_CHANGE op was involved
This commit is contained in:
commit
be37f21a08
@ -66,7 +66,7 @@ static void tty_audit_log(const char *description, dev_t dev,
|
||||
uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
|
||||
unsigned int sessionid = audit_get_sessionid(current);
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
|
||||
ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_TTY);
|
||||
if (ab) {
|
||||
char name[sizeof(current->comm)];
|
||||
|
||||
|
@ -2720,7 +2720,7 @@ filename_mountpoint(int dfd, struct filename *name, struct path *path,
|
||||
if (unlikely(error == -ESTALE))
|
||||
error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path);
|
||||
if (likely(!error))
|
||||
audit_inode(name, path->dentry, 0);
|
||||
audit_inode(name, path->dentry, flags & LOOKUP_NO_EVAL);
|
||||
restore_nameidata();
|
||||
putname(name);
|
||||
return error;
|
||||
|
@ -1640,6 +1640,8 @@ int ksys_umount(char __user *name, int flags)
|
||||
if (!(flags & UMOUNT_NOFOLLOW))
|
||||
lookup_flags |= LOOKUP_FOLLOW;
|
||||
|
||||
lookup_flags |= LOOKUP_NO_EVAL;
|
||||
|
||||
retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
@ -1210,7 +1210,7 @@ static const struct file_operations proc_oom_score_adj_operations = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
#ifdef CONFIG_AUDIT
|
||||
#define TMPBUFLEN 11
|
||||
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@ -3044,7 +3044,7 @@ static const struct pid_entry tgid_base_stuff[] = {
|
||||
ONE("oom_score", S_IRUGO, proc_oom_score),
|
||||
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
|
||||
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
#ifdef CONFIG_AUDIT
|
||||
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|
||||
REG("sessionid", S_IRUGO, proc_sessionid_operations),
|
||||
#endif
|
||||
@ -3432,7 +3432,7 @@ static const struct pid_entry tid_base_stuff[] = {
|
||||
ONE("oom_score", S_IRUGO, proc_oom_score),
|
||||
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
|
||||
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
#ifdef CONFIG_AUDIT
|
||||
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|
||||
REG("sessionid", S_IRUGO, proc_sessionid_operations),
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/namei.h> /* LOOKUP_* */
|
||||
#include <uapi/linux/audit.h>
|
||||
|
||||
#define AUDIT_INO_UNSET ((unsigned long)-1)
|
||||
@ -159,6 +160,18 @@ extern int audit_update_lsm_rules(void);
|
||||
extern int audit_rule_change(int type, int seq, void *data, size_t datasz);
|
||||
extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);
|
||||
|
||||
extern int audit_set_loginuid(kuid_t loginuid);
|
||||
|
||||
static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
|
||||
{
|
||||
return tsk->loginuid;
|
||||
}
|
||||
|
||||
static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
|
||||
{
|
||||
return tsk->sessionid;
|
||||
}
|
||||
|
||||
extern u32 audit_enabled;
|
||||
#else /* CONFIG_AUDIT */
|
||||
static inline __printf(4, 5)
|
||||
@ -201,6 +214,17 @@ static inline int audit_log_task_context(struct audit_buffer *ab)
|
||||
}
|
||||
static inline void audit_log_task_info(struct audit_buffer *ab)
|
||||
{ }
|
||||
|
||||
static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
|
||||
{
|
||||
return INVALID_UID;
|
||||
}
|
||||
|
||||
static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
|
||||
{
|
||||
return AUDIT_SID_UNSET;
|
||||
}
|
||||
|
||||
#define audit_enabled AUDIT_OFF
|
||||
#endif /* CONFIG_AUDIT */
|
||||
|
||||
@ -225,6 +249,7 @@ extern void __audit_getname(struct filename *name);
|
||||
|
||||
#define AUDIT_INODE_PARENT 1 /* dentry represents the parent */
|
||||
#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */
|
||||
#define AUDIT_INODE_NOEVAL 4 /* audit record incomplete */
|
||||
extern void __audit_inode(struct filename *name, const struct dentry *dentry,
|
||||
unsigned int flags);
|
||||
extern void __audit_file(const struct file *);
|
||||
@ -285,12 +310,15 @@ static inline void audit_getname(struct filename *name)
|
||||
}
|
||||
static inline void audit_inode(struct filename *name,
|
||||
const struct dentry *dentry,
|
||||
unsigned int parent) {
|
||||
unsigned int flags) {
|
||||
if (unlikely(!audit_dummy_context())) {
|
||||
unsigned int flags = 0;
|
||||
if (parent)
|
||||
flags |= AUDIT_INODE_PARENT;
|
||||
__audit_inode(name, dentry, flags);
|
||||
unsigned int aflags = 0;
|
||||
|
||||
if (flags & LOOKUP_PARENT)
|
||||
aflags |= AUDIT_INODE_PARENT;
|
||||
if (flags & LOOKUP_NO_EVAL)
|
||||
aflags |= AUDIT_INODE_NOEVAL;
|
||||
__audit_inode(name, dentry, aflags);
|
||||
}
|
||||
}
|
||||
static inline void audit_file(struct file *file)
|
||||
@ -320,21 +348,6 @@ static inline void audit_ptrace(struct task_struct *t)
|
||||
}
|
||||
|
||||
/* Private API (for audit.c only) */
|
||||
extern unsigned int audit_serial(void);
|
||||
extern int auditsc_get_stamp(struct audit_context *ctx,
|
||||
struct timespec64 *t, unsigned int *serial);
|
||||
extern int audit_set_loginuid(kuid_t loginuid);
|
||||
|
||||
static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
|
||||
{
|
||||
return tsk->loginuid;
|
||||
}
|
||||
|
||||
static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
|
||||
{
|
||||
return tsk->sessionid;
|
||||
}
|
||||
|
||||
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 void __audit_bprm(struct linux_binprm *bprm);
|
||||
@ -514,19 +527,6 @@ 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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
|
||||
{
|
||||
return INVALID_UID;
|
||||
}
|
||||
static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
|
||||
{
|
||||
return AUDIT_SID_UNSET;
|
||||
}
|
||||
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
|
||||
{ }
|
||||
static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid,
|
||||
|
@ -14,7 +14,7 @@
|
||||
#define _LINUX_CAPABILITY_H
|
||||
|
||||
#include <uapi/linux/capability.h>
|
||||
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
#define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3
|
||||
#define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3
|
||||
@ -25,11 +25,12 @@ typedef struct kernel_cap_struct {
|
||||
__u32 cap[_KERNEL_CAPABILITY_U32S];
|
||||
} kernel_cap_t;
|
||||
|
||||
/* exact same as vfs_cap_data but in cpu endian and always filled completely */
|
||||
/* same as vfs_ns_cap_data but in cpu endian and always filled completely */
|
||||
struct cpu_vfs_cap_data {
|
||||
__u32 magic_etc;
|
||||
kernel_cap_t permitted;
|
||||
kernel_cap_t inheritable;
|
||||
kuid_t rootid;
|
||||
};
|
||||
|
||||
#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
|
||||
|
@ -1344,7 +1344,6 @@
|
||||
* @field contains the field which relates to current LSM.
|
||||
* @op contains the operator that will be used for matching.
|
||||
* @rule points to the audit rule that will be checked against.
|
||||
* @actx points to the audit context associated with the check.
|
||||
* Return 1 if secid matches the rule, 0 if it does not, -ERRNO on failure.
|
||||
*
|
||||
* @audit_rule_free:
|
||||
@ -1766,8 +1765,7 @@ union security_list_options {
|
||||
int (*audit_rule_init)(u32 field, u32 op, char *rulestr,
|
||||
void **lsmrule);
|
||||
int (*audit_rule_known)(struct audit_krule *krule);
|
||||
int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule,
|
||||
struct audit_context *actx);
|
||||
int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule);
|
||||
void (*audit_rule_free)(void *lsmrule);
|
||||
#endif /* CONFIG_AUDIT */
|
||||
|
||||
|
@ -24,6 +24,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
||||
* - internal "there are more path components" flag
|
||||
* - dentry cache is untrusted; force a real lookup
|
||||
* - suppress terminal automount
|
||||
* - skip revalidation
|
||||
* - don't fetch xattrs on audit_inode
|
||||
*/
|
||||
#define LOOKUP_FOLLOW 0x0001
|
||||
#define LOOKUP_DIRECTORY 0x0002
|
||||
@ -33,6 +35,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
||||
#define LOOKUP_REVAL 0x0020
|
||||
#define LOOKUP_RCU 0x0040
|
||||
#define LOOKUP_NO_REVAL 0x0080
|
||||
#define LOOKUP_NO_EVAL 0x0100
|
||||
|
||||
/*
|
||||
* Intent data
|
||||
|
@ -872,8 +872,10 @@ struct task_struct {
|
||||
|
||||
struct callback_head *task_works;
|
||||
|
||||
struct audit_context *audit_context;
|
||||
#ifdef CONFIG_AUDIT
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
struct audit_context *audit_context;
|
||||
#endif
|
||||
kuid_t loginuid;
|
||||
unsigned int sessionid;
|
||||
#endif
|
||||
|
@ -1679,8 +1679,7 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
|
||||
#ifdef CONFIG_SECURITY
|
||||
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,
|
||||
struct audit_context *actx);
|
||||
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
|
||||
void security_audit_rule_free(void *lsmrule);
|
||||
|
||||
#else
|
||||
@ -1697,7 +1696,7 @@ static inline int security_audit_rule_known(struct audit_krule *krule)
|
||||
}
|
||||
|
||||
static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
|
||||
void *lsmrule, struct audit_context *actx)
|
||||
void *lsmrule)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ struct task_struct init_task
|
||||
.thread_pid = &init_struct_pid,
|
||||
.thread_group = LIST_HEAD_INIT(init_task.thread_group),
|
||||
.thread_node = LIST_HEAD_INIT(init_signals.thread_head),
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
#ifdef CONFIG_AUDIT
|
||||
.loginuid = INVALID_UID,
|
||||
.sessionid = AUDIT_SID_UNSET,
|
||||
#endif
|
||||
|
267
kernel/audit.c
267
kernel/audit.c
@ -396,10 +396,10 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old,
|
||||
struct audit_buffer *ab;
|
||||
int rc = 0;
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
|
||||
ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE);
|
||||
if (unlikely(!ab))
|
||||
return rc;
|
||||
audit_log_format(ab, "%s=%u old=%u ", function_name, new, old);
|
||||
audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old);
|
||||
audit_log_session_info(ab);
|
||||
rc = audit_log_task_context(ab);
|
||||
if (rc)
|
||||
@ -1053,7 +1053,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
|
||||
static void audit_log_common_recv_msg(struct audit_context *context,
|
||||
struct audit_buffer **ab, u16 msg_type)
|
||||
{
|
||||
uid_t uid = from_kuid(&init_user_ns, current_uid());
|
||||
pid_t pid = task_tgid_nr(current);
|
||||
@ -1063,7 +1064,7 @@ static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
|
||||
return;
|
||||
}
|
||||
|
||||
*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
|
||||
*ab = audit_log_start(context, GFP_KERNEL, msg_type);
|
||||
if (unlikely(!*ab))
|
||||
return;
|
||||
audit_log_format(*ab, "pid=%d uid=%u ", pid, uid);
|
||||
@ -1071,6 +1072,12 @@ static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
|
||||
audit_log_task_context(*ab);
|
||||
}
|
||||
|
||||
static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
|
||||
u16 msg_type)
|
||||
{
|
||||
audit_log_common_recv_msg(NULL, ab, msg_type);
|
||||
}
|
||||
|
||||
int is_audit_feature_set(int i)
|
||||
{
|
||||
return af.features & AUDIT_FEATURE_TO_MASK(i);
|
||||
@ -1338,7 +1345,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
audit_log_common_recv_msg(&ab, msg_type);
|
||||
audit_log_user_recv_msg(&ab, msg_type);
|
||||
if (msg_type != AUDIT_USER_TTY)
|
||||
audit_log_format(ab, " msg='%.*s'",
|
||||
AUDIT_MESSAGE_TEXT_MAX,
|
||||
@ -1361,8 +1368,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
|
||||
return -EINVAL;
|
||||
if (audit_enabled == AUDIT_LOCKED) {
|
||||
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
|
||||
audit_log_format(ab, " audit_enabled=%d res=0", audit_enabled);
|
||||
audit_log_common_recv_msg(audit_context(), &ab,
|
||||
AUDIT_CONFIG_CHANGE);
|
||||
audit_log_format(ab, " op=%s audit_enabled=%d res=0",
|
||||
msg_type == AUDIT_ADD_RULE ?
|
||||
"add_rule" : "remove_rule",
|
||||
audit_enabled);
|
||||
audit_log_end(ab);
|
||||
return -EPERM;
|
||||
}
|
||||
@ -1373,7 +1384,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
break;
|
||||
case AUDIT_TRIM:
|
||||
audit_trim_trees();
|
||||
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
|
||||
audit_log_common_recv_msg(audit_context(), &ab,
|
||||
AUDIT_CONFIG_CHANGE);
|
||||
audit_log_format(ab, " op=trim res=1");
|
||||
audit_log_end(ab);
|
||||
break;
|
||||
@ -1403,8 +1415,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
/* OK, here comes... */
|
||||
err = audit_tag_tree(old, new);
|
||||
|
||||
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
|
||||
|
||||
audit_log_common_recv_msg(audit_context(), &ab,
|
||||
AUDIT_CONFIG_CHANGE);
|
||||
audit_log_format(ab, " op=make_equiv old=");
|
||||
audit_log_untrustedstring(ab, old);
|
||||
audit_log_format(ab, " new=");
|
||||
@ -1471,7 +1483,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
old.enabled = t & AUDIT_TTY_ENABLE;
|
||||
old.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD);
|
||||
|
||||
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
|
||||
audit_log_common_recv_msg(audit_context(), &ab,
|
||||
AUDIT_CONFIG_CHANGE);
|
||||
audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d"
|
||||
" old-log_passwd=%d new-log_passwd=%d res=%d",
|
||||
old.enabled, s.enabled, old.log_passwd,
|
||||
@ -2054,153 +2067,6 @@ void audit_log_key(struct audit_buffer *ab, char *key)
|
||||
audit_log_format(ab, "(null)");
|
||||
}
|
||||
|
||||
void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cap_isclear(*cap)) {
|
||||
audit_log_format(ab, " %s=0", prefix);
|
||||
return;
|
||||
}
|
||||
audit_log_format(ab, " %s=", prefix);
|
||||
CAP_FOR_EACH_U32(i)
|
||||
audit_log_format(ab, "%08x", cap->cap[CAP_LAST_U32 - i]);
|
||||
}
|
||||
|
||||
static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
|
||||
{
|
||||
audit_log_cap(ab, "cap_fp", &name->fcap.permitted);
|
||||
audit_log_cap(ab, "cap_fi", &name->fcap.inheritable);
|
||||
audit_log_format(ab, " cap_fe=%d cap_fver=%x",
|
||||
name->fcap.fE, name->fcap_ver);
|
||||
}
|
||||
|
||||
static inline int audit_copy_fcaps(struct audit_names *name,
|
||||
const struct dentry *dentry)
|
||||
{
|
||||
struct cpu_vfs_cap_data caps;
|
||||
int rc;
|
||||
|
||||
if (!dentry)
|
||||
return 0;
|
||||
|
||||
rc = get_vfs_caps_from_disk(dentry, &caps);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
name->fcap.permitted = caps.permitted;
|
||||
name->fcap.inheritable = caps.inheritable;
|
||||
name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
|
||||
name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >>
|
||||
VFS_CAP_REVISION_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy inode data into an audit_names. */
|
||||
void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
|
||||
struct inode *inode)
|
||||
{
|
||||
name->ino = inode->i_ino;
|
||||
name->dev = inode->i_sb->s_dev;
|
||||
name->mode = inode->i_mode;
|
||||
name->uid = inode->i_uid;
|
||||
name->gid = inode->i_gid;
|
||||
name->rdev = inode->i_rdev;
|
||||
security_inode_getsecid(inode, &name->osid);
|
||||
audit_copy_fcaps(name, dentry);
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_log_name - produce AUDIT_PATH record from struct audit_names
|
||||
* @context: audit_context for the task
|
||||
* @n: audit_names structure with reportable details
|
||||
* @path: optional path to report instead of audit_names->name
|
||||
* @record_num: record number to report when handling a list of names
|
||||
* @call_panic: optional pointer to int that will be updated if secid fails
|
||||
*/
|
||||
void audit_log_name(struct audit_context *context, struct audit_names *n,
|
||||
const struct path *path, int record_num, int *call_panic)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
|
||||
if (!ab)
|
||||
return;
|
||||
|
||||
audit_log_format(ab, "item=%d", record_num);
|
||||
|
||||
if (path)
|
||||
audit_log_d_path(ab, " name=", path);
|
||||
else if (n->name) {
|
||||
switch (n->name_len) {
|
||||
case AUDIT_NAME_FULL:
|
||||
/* log the full path */
|
||||
audit_log_format(ab, " name=");
|
||||
audit_log_untrustedstring(ab, n->name->name);
|
||||
break;
|
||||
case 0:
|
||||
/* name was specified as a relative path and the
|
||||
* directory component is the cwd */
|
||||
audit_log_d_path(ab, " name=", &context->pwd);
|
||||
break;
|
||||
default:
|
||||
/* log the name's directory component */
|
||||
audit_log_format(ab, " name=");
|
||||
audit_log_n_untrustedstring(ab, n->name->name,
|
||||
n->name_len);
|
||||
}
|
||||
} else
|
||||
audit_log_format(ab, " name=(null)");
|
||||
|
||||
if (n->ino != AUDIT_INO_UNSET)
|
||||
audit_log_format(ab, " inode=%lu"
|
||||
" dev=%02x:%02x mode=%#ho"
|
||||
" ouid=%u ogid=%u rdev=%02x:%02x",
|
||||
n->ino,
|
||||
MAJOR(n->dev),
|
||||
MINOR(n->dev),
|
||||
n->mode,
|
||||
from_kuid(&init_user_ns, n->uid),
|
||||
from_kgid(&init_user_ns, n->gid),
|
||||
MAJOR(n->rdev),
|
||||
MINOR(n->rdev));
|
||||
if (n->osid != 0) {
|
||||
char *ctx = NULL;
|
||||
u32 len;
|
||||
if (security_secid_to_secctx(
|
||||
n->osid, &ctx, &len)) {
|
||||
audit_log_format(ab, " osid=%u", n->osid);
|
||||
if (call_panic)
|
||||
*call_panic = 2;
|
||||
} else {
|
||||
audit_log_format(ab, " obj=%s", ctx);
|
||||
security_release_secctx(ctx, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* log the audit_names record type */
|
||||
switch(n->type) {
|
||||
case AUDIT_TYPE_NORMAL:
|
||||
audit_log_format(ab, " nametype=NORMAL");
|
||||
break;
|
||||
case AUDIT_TYPE_PARENT:
|
||||
audit_log_format(ab, " nametype=PARENT");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_DELETE:
|
||||
audit_log_format(ab, " nametype=DELETE");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_CREATE:
|
||||
audit_log_format(ab, " nametype=CREATE");
|
||||
break;
|
||||
default:
|
||||
audit_log_format(ab, " nametype=UNKNOWN");
|
||||
break;
|
||||
}
|
||||
|
||||
audit_log_fcaps(ab, n);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
int audit_log_task_context(struct audit_buffer *ab)
|
||||
{
|
||||
char *ctx = NULL;
|
||||
@ -2322,6 +2188,91 @@ void audit_log_link_denied(const char *operation)
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
/* 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, oldloginuid, loginuid;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!audit_enabled)
|
||||
return;
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
|
||||
if (!ab)
|
||||
return;
|
||||
|
||||
uid = from_kuid(&init_user_ns, task_uid(current));
|
||||
oldloginuid = from_kuid(&init_user_ns, koldloginuid);
|
||||
loginuid = from_kuid(&init_user_ns, kloginuid),
|
||||
tty = audit_get_tty();
|
||||
|
||||
audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
|
||||
audit_log_task_context(ab);
|
||||
audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
|
||||
oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
|
||||
oldsessionid, sessionid, !rc);
|
||||
audit_put_tty(tty);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_set_loginuid - set current task's loginuid
|
||||
* @loginuid: loginuid value
|
||||
*
|
||||
* Returns 0.
|
||||
*
|
||||
* Called (set) from fs/proc/base.c::proc_loginuid_write().
|
||||
*/
|
||||
int audit_set_loginuid(kuid_t loginuid)
|
||||
{
|
||||
unsigned int oldsessionid, sessionid = AUDIT_SID_UNSET;
|
||||
kuid_t oldloginuid;
|
||||
int rc;
|
||||
|
||||
oldloginuid = audit_get_loginuid(current);
|
||||
oldsessionid = audit_get_sessionid(current);
|
||||
|
||||
rc = audit_set_loginuid_perm(loginuid);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* are we setting or clearing? */
|
||||
if (uid_valid(loginuid)) {
|
||||
sessionid = (unsigned int)atomic_inc_return(&session_id);
|
||||
if (unlikely(sessionid == AUDIT_SID_UNSET))
|
||||
sessionid = (unsigned int)atomic_inc_return(&session_id);
|
||||
}
|
||||
|
||||
current->sessionid = sessionid;
|
||||
current->loginuid = loginuid;
|
||||
out:
|
||||
audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_log_end - end one audit record
|
||||
* @ab: the audit_buffer
|
||||
|
@ -69,6 +69,7 @@ struct audit_cap_data {
|
||||
kernel_cap_t effective; /* effective set of process */
|
||||
};
|
||||
kernel_cap_t ambient;
|
||||
kuid_t rootid;
|
||||
};
|
||||
|
||||
/* When fs/namei.c:getname() is called, we store the pointer in name and bump
|
||||
@ -212,15 +213,6 @@ extern bool audit_ever_enabled;
|
||||
|
||||
extern void audit_log_session_info(struct audit_buffer *ab);
|
||||
|
||||
extern void audit_copy_inode(struct audit_names *name,
|
||||
const struct dentry *dentry,
|
||||
struct inode *inode);
|
||||
extern void audit_log_cap(struct audit_buffer *ab, char *prefix,
|
||||
kernel_cap_t *cap);
|
||||
extern void audit_log_name(struct audit_context *context,
|
||||
struct audit_names *n, const struct path *path,
|
||||
int record_num, int *call_panic);
|
||||
|
||||
extern int auditd_test_task(struct task_struct *task);
|
||||
|
||||
#define AUDIT_INODE_BUCKETS 32
|
||||
@ -267,25 +259,52 @@ extern void audit_log_d_path_exe(struct audit_buffer *ab,
|
||||
extern struct tty_struct *audit_get_tty(void);
|
||||
extern void audit_put_tty(struct tty_struct *tty);
|
||||
|
||||
/* audit watch functions */
|
||||
/* audit watch/mark/tree functions */
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
extern unsigned int audit_serial(void);
|
||||
extern int auditsc_get_stamp(struct audit_context *ctx,
|
||||
struct timespec64 *t, unsigned int *serial);
|
||||
|
||||
extern void audit_put_watch(struct audit_watch *watch);
|
||||
extern void audit_get_watch(struct audit_watch *watch);
|
||||
extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
|
||||
extern int audit_to_watch(struct audit_krule *krule, char *path, int len,
|
||||
u32 op);
|
||||
extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
|
||||
extern void audit_remove_watch_rule(struct audit_krule *krule);
|
||||
extern char *audit_watch_path(struct audit_watch *watch);
|
||||
extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
|
||||
extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino,
|
||||
dev_t dev);
|
||||
|
||||
extern struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len);
|
||||
extern struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule,
|
||||
char *pathname, int len);
|
||||
extern char *audit_mark_path(struct audit_fsnotify_mark *mark);
|
||||
extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark);
|
||||
extern void audit_remove_mark_rule(struct audit_krule *krule);
|
||||
extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev);
|
||||
extern int audit_mark_compare(struct audit_fsnotify_mark *mark,
|
||||
unsigned long ino, dev_t dev);
|
||||
extern int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old);
|
||||
extern int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark);
|
||||
extern int audit_exe_compare(struct task_struct *tsk,
|
||||
struct audit_fsnotify_mark *mark);
|
||||
|
||||
#else
|
||||
extern struct audit_chunk *audit_tree_lookup(const struct inode *inode);
|
||||
extern void audit_put_chunk(struct audit_chunk *chunk);
|
||||
extern bool audit_tree_match(struct audit_chunk *chunk,
|
||||
struct audit_tree *tree);
|
||||
extern int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op);
|
||||
extern int audit_add_tree_rule(struct audit_krule *rule);
|
||||
extern int audit_remove_tree_rule(struct audit_krule *rule);
|
||||
extern void audit_trim_trees(void);
|
||||
extern int audit_tag_tree(char *old, char *new);
|
||||
extern const char *audit_tree_path(struct audit_tree *tree);
|
||||
extern void audit_put_tree(struct audit_tree *tree);
|
||||
extern void audit_kill_trees(struct audit_context *context);
|
||||
|
||||
extern int audit_signal_info(int sig, struct task_struct *t);
|
||||
extern void audit_filter_inodes(struct task_struct *tsk,
|
||||
struct audit_context *ctx);
|
||||
extern struct list_head *audit_killed_trees(void);
|
||||
#else /* CONFIG_AUDITSYSCALL */
|
||||
#define auditsc_get_stamp(c, t, s) 0
|
||||
#define audit_put_watch(w) {}
|
||||
#define audit_get_watch(w) {}
|
||||
#define audit_to_watch(k, p, l, o) (-EINVAL)
|
||||
@ -301,21 +320,7 @@ extern int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark
|
||||
#define audit_mark_compare(m, i, d) 0
|
||||
#define audit_exe_compare(t, m) (-EINVAL)
|
||||
#define audit_dupe_exe(n, o) (-EINVAL)
|
||||
#endif /* CONFIG_AUDITSYSCALL */
|
||||
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
extern struct audit_chunk *audit_tree_lookup(const struct inode *inode);
|
||||
extern void audit_put_chunk(struct audit_chunk *chunk);
|
||||
extern bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree);
|
||||
extern int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op);
|
||||
extern int audit_add_tree_rule(struct audit_krule *rule);
|
||||
extern int audit_remove_tree_rule(struct audit_krule *rule);
|
||||
extern void audit_trim_trees(void);
|
||||
extern int audit_tag_tree(char *old, char *new);
|
||||
extern const char *audit_tree_path(struct audit_tree *tree);
|
||||
extern void audit_put_tree(struct audit_tree *tree);
|
||||
extern void audit_kill_trees(struct list_head *list);
|
||||
#else
|
||||
#define audit_remove_tree_rule(rule) BUG()
|
||||
#define audit_add_tree_rule(rule) -EINVAL
|
||||
#define audit_make_tree(rule, str, op) -EINVAL
|
||||
@ -323,8 +328,11 @@ extern void audit_kill_trees(struct list_head *list);
|
||||
#define audit_put_tree(tree) (void)0
|
||||
#define audit_tag_tree(old, new) -EINVAL
|
||||
#define audit_tree_path(rule) "" /* never called */
|
||||
#define audit_kill_trees(list) BUG()
|
||||
#endif
|
||||
#define audit_kill_trees(context) BUG()
|
||||
|
||||
#define audit_signal_info(s, t) AUDIT_DISABLED
|
||||
#define audit_filter_inodes(t, c) AUDIT_DISABLED
|
||||
#endif /* CONFIG_AUDITSYSCALL */
|
||||
|
||||
extern char *audit_unpack_string(void **bufp, size_t *remain, size_t len);
|
||||
|
||||
@ -334,14 +342,5 @@ extern u32 audit_sig_sid;
|
||||
|
||||
extern int audit_filter(int msgtype, unsigned int listtype);
|
||||
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
extern int audit_signal_info(int sig, struct task_struct *t);
|
||||
extern void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx);
|
||||
extern struct list_head *audit_killed_trees(void);
|
||||
#else
|
||||
#define audit_signal_info(s,t) AUDIT_DISABLED
|
||||
#define audit_filter_inodes(t,c) AUDIT_DISABLED
|
||||
#endif
|
||||
|
||||
extern void audit_ctl_lock(void);
|
||||
extern void audit_ctl_unlock(void);
|
||||
|
@ -127,7 +127,7 @@ static void audit_mark_log_rule_change(struct audit_fsnotify_mark *audit_mark, c
|
||||
|
||||
if (!audit_enabled)
|
||||
return;
|
||||
ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
|
||||
ab = audit_log_start(audit_context(), GFP_NOFS, AUDIT_CONFIG_CHANGE);
|
||||
if (unlikely(!ab))
|
||||
return;
|
||||
audit_log_session_info(ab);
|
||||
|
@ -524,13 +524,14 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void audit_tree_log_remove_rule(struct audit_krule *rule)
|
||||
static void audit_tree_log_remove_rule(struct audit_context *context,
|
||||
struct audit_krule *rule)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
|
||||
if (!audit_enabled)
|
||||
return;
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
|
||||
ab = audit_log_start(context, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
|
||||
if (unlikely(!ab))
|
||||
return;
|
||||
audit_log_format(ab, "op=remove_rule dir=");
|
||||
@ -540,7 +541,7 @@ static void audit_tree_log_remove_rule(struct audit_krule *rule)
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
static void kill_rules(struct audit_tree *tree)
|
||||
static void kill_rules(struct audit_context *context, struct audit_tree *tree)
|
||||
{
|
||||
struct audit_krule *rule, *next;
|
||||
struct audit_entry *entry;
|
||||
@ -551,7 +552,7 @@ static void kill_rules(struct audit_tree *tree)
|
||||
list_del_init(&rule->rlist);
|
||||
if (rule->tree) {
|
||||
/* not a half-baked one */
|
||||
audit_tree_log_remove_rule(rule);
|
||||
audit_tree_log_remove_rule(context, rule);
|
||||
if (entry->rule.exe)
|
||||
audit_remove_mark(entry->rule.exe);
|
||||
rule->tree = NULL;
|
||||
@ -633,7 +634,7 @@ static void trim_marked(struct audit_tree *tree)
|
||||
tree->goner = 1;
|
||||
spin_unlock(&hash_lock);
|
||||
mutex_lock(&audit_filter_mutex);
|
||||
kill_rules(tree);
|
||||
kill_rules(audit_context(), tree);
|
||||
list_del_init(&tree->list);
|
||||
mutex_unlock(&audit_filter_mutex);
|
||||
prune_one(tree);
|
||||
@ -973,8 +974,10 @@ static void audit_schedule_prune(void)
|
||||
* ... and that one is done if evict_chunk() decides to delay until the end
|
||||
* of syscall. Runs synchronously.
|
||||
*/
|
||||
void audit_kill_trees(struct list_head *list)
|
||||
void audit_kill_trees(struct audit_context *context)
|
||||
{
|
||||
struct list_head *list = &context->killed_trees;
|
||||
|
||||
audit_ctl_lock();
|
||||
mutex_lock(&audit_filter_mutex);
|
||||
|
||||
@ -982,7 +985,7 @@ void audit_kill_trees(struct list_head *list)
|
||||
struct audit_tree *victim;
|
||||
|
||||
victim = list_entry(list->next, struct audit_tree, list);
|
||||
kill_rules(victim);
|
||||
kill_rules(context, victim);
|
||||
list_del_init(&victim->list);
|
||||
|
||||
mutex_unlock(&audit_filter_mutex);
|
||||
@ -1017,7 +1020,7 @@ static void evict_chunk(struct audit_chunk *chunk)
|
||||
list_del_init(&owner->same_root);
|
||||
spin_unlock(&hash_lock);
|
||||
if (!postponed) {
|
||||
kill_rules(owner);
|
||||
kill_rules(audit_context(), owner);
|
||||
list_move(&owner->list, &prune_list);
|
||||
need_prune = 1;
|
||||
} else {
|
||||
|
@ -242,7 +242,7 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc
|
||||
|
||||
if (!audit_enabled)
|
||||
return;
|
||||
ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
|
||||
ab = audit_log_start(audit_context(), GFP_NOFS, AUDIT_CONFIG_CHANGE);
|
||||
if (!ab)
|
||||
return;
|
||||
audit_log_session_info(ab);
|
||||
|
@ -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;
|
||||
}
|
||||
@ -1091,7 +1091,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
|
||||
if (!audit_enabled)
|
||||
return;
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
|
||||
ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE);
|
||||
if (!ab)
|
||||
return;
|
||||
audit_log_session_info(ab);
|
||||
@ -1355,7 +1355,7 @@ int audit_filter(int msgtype, unsigned int listtype)
|
||||
if (f->lsm_rule) {
|
||||
security_task_getsecid(current, &sid);
|
||||
result = security_audit_rule_match(sid,
|
||||
f->type, f->op, f->lsm_rule, NULL);
|
||||
f->type, f->op, f->lsm_rule);
|
||||
}
|
||||
break;
|
||||
case AUDIT_EXE:
|
||||
|
320
kernel/auditsc.c
320
kernel/auditsc.c
@ -631,9 +631,8 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
need_sid = 0;
|
||||
}
|
||||
result = security_audit_rule_match(sid, f->type,
|
||||
f->op,
|
||||
f->lsm_rule,
|
||||
ctx);
|
||||
f->op,
|
||||
f->lsm_rule);
|
||||
}
|
||||
break;
|
||||
case AUDIT_OBJ_USER:
|
||||
@ -647,13 +646,17 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
/* Find files that match */
|
||||
if (name) {
|
||||
result = security_audit_rule_match(
|
||||
name->osid, f->type, f->op,
|
||||
f->lsm_rule, ctx);
|
||||
name->osid,
|
||||
f->type,
|
||||
f->op,
|
||||
f->lsm_rule);
|
||||
} else if (ctx) {
|
||||
list_for_each_entry(n, &ctx->names_list, list) {
|
||||
if (security_audit_rule_match(n->osid, f->type,
|
||||
f->op, f->lsm_rule,
|
||||
ctx)) {
|
||||
if (security_audit_rule_match(
|
||||
n->osid,
|
||||
f->type,
|
||||
f->op,
|
||||
f->lsm_rule)) {
|
||||
++result;
|
||||
break;
|
||||
}
|
||||
@ -664,7 +667,7 @@ static int audit_filter_rules(struct task_struct *tsk,
|
||||
break;
|
||||
if (security_audit_rule_match(ctx->ipc.osid,
|
||||
f->type, f->op,
|
||||
f->lsm_rule, ctx))
|
||||
f->lsm_rule))
|
||||
++result;
|
||||
}
|
||||
break;
|
||||
@ -1136,6 +1139,32 @@ out:
|
||||
kfree(buf_head);
|
||||
}
|
||||
|
||||
void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cap_isclear(*cap)) {
|
||||
audit_log_format(ab, " %s=0", prefix);
|
||||
return;
|
||||
}
|
||||
audit_log_format(ab, " %s=", prefix);
|
||||
CAP_FOR_EACH_U32(i)
|
||||
audit_log_format(ab, "%08x", cap->cap[CAP_LAST_U32 - i]);
|
||||
}
|
||||
|
||||
static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
|
||||
{
|
||||
if (name->fcap_ver == -1) {
|
||||
audit_log_format(ab, " cap_fe=? cap_fver=? cap_fp=? cap_fi=?");
|
||||
return;
|
||||
}
|
||||
audit_log_cap(ab, "cap_fp", &name->fcap.permitted);
|
||||
audit_log_cap(ab, "cap_fi", &name->fcap.inheritable);
|
||||
audit_log_format(ab, " cap_fe=%d cap_fver=%x cap_frootid=%d",
|
||||
name->fcap.fE, name->fcap_ver,
|
||||
from_kuid(&init_user_ns, name->fcap.rootid));
|
||||
}
|
||||
|
||||
static void show_special(struct audit_context *context, int *call_panic)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
@ -1258,6 +1287,97 @@ static inline int audit_proctitle_rtrim(char *proctitle, int len)
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* audit_log_name - produce AUDIT_PATH record from struct audit_names
|
||||
* @context: audit_context for the task
|
||||
* @n: audit_names structure with reportable details
|
||||
* @path: optional path to report instead of audit_names->name
|
||||
* @record_num: record number to report when handling a list of names
|
||||
* @call_panic: optional pointer to int that will be updated if secid fails
|
||||
*/
|
||||
static void audit_log_name(struct audit_context *context, struct audit_names *n,
|
||||
const struct path *path, int record_num, int *call_panic)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
|
||||
ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
|
||||
if (!ab)
|
||||
return;
|
||||
|
||||
audit_log_format(ab, "item=%d", record_num);
|
||||
|
||||
if (path)
|
||||
audit_log_d_path(ab, " name=", path);
|
||||
else if (n->name) {
|
||||
switch (n->name_len) {
|
||||
case AUDIT_NAME_FULL:
|
||||
/* log the full path */
|
||||
audit_log_format(ab, " name=");
|
||||
audit_log_untrustedstring(ab, n->name->name);
|
||||
break;
|
||||
case 0:
|
||||
/* name was specified as a relative path and the
|
||||
* directory component is the cwd
|
||||
*/
|
||||
audit_log_d_path(ab, " name=", &context->pwd);
|
||||
break;
|
||||
default:
|
||||
/* log the name's directory component */
|
||||
audit_log_format(ab, " name=");
|
||||
audit_log_n_untrustedstring(ab, n->name->name,
|
||||
n->name_len);
|
||||
}
|
||||
} else
|
||||
audit_log_format(ab, " name=(null)");
|
||||
|
||||
if (n->ino != AUDIT_INO_UNSET)
|
||||
audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#ho ouid=%u ogid=%u rdev=%02x:%02x",
|
||||
n->ino,
|
||||
MAJOR(n->dev),
|
||||
MINOR(n->dev),
|
||||
n->mode,
|
||||
from_kuid(&init_user_ns, n->uid),
|
||||
from_kgid(&init_user_ns, n->gid),
|
||||
MAJOR(n->rdev),
|
||||
MINOR(n->rdev));
|
||||
if (n->osid != 0) {
|
||||
char *ctx = NULL;
|
||||
u32 len;
|
||||
|
||||
if (security_secid_to_secctx(
|
||||
n->osid, &ctx, &len)) {
|
||||
audit_log_format(ab, " osid=%u", n->osid);
|
||||
if (call_panic)
|
||||
*call_panic = 2;
|
||||
} else {
|
||||
audit_log_format(ab, " obj=%s", ctx);
|
||||
security_release_secctx(ctx, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* log the audit_names record type */
|
||||
switch (n->type) {
|
||||
case AUDIT_TYPE_NORMAL:
|
||||
audit_log_format(ab, " nametype=NORMAL");
|
||||
break;
|
||||
case AUDIT_TYPE_PARENT:
|
||||
audit_log_format(ab, " nametype=PARENT");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_DELETE:
|
||||
audit_log_format(ab, " nametype=DELETE");
|
||||
break;
|
||||
case AUDIT_TYPE_CHILD_CREATE:
|
||||
audit_log_format(ab, " nametype=CREATE");
|
||||
break;
|
||||
default:
|
||||
audit_log_format(ab, " nametype=UNKNOWN");
|
||||
break;
|
||||
}
|
||||
|
||||
audit_log_fcaps(ab, n);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
static void audit_log_proctitle(void)
|
||||
{
|
||||
int res;
|
||||
@ -1358,6 +1478,9 @@ static void audit_log_exit(void)
|
||||
audit_log_cap(ab, "pi", &axs->new_pcap.inheritable);
|
||||
audit_log_cap(ab, "pe", &axs->new_pcap.effective);
|
||||
audit_log_cap(ab, "pa", &axs->new_pcap.ambient);
|
||||
audit_log_format(ab, " frootid=%d",
|
||||
from_kuid(&init_user_ns,
|
||||
axs->fcap.rootid));
|
||||
break; }
|
||||
|
||||
}
|
||||
@ -1444,6 +1567,9 @@ void __audit_free(struct task_struct *tsk)
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (!list_empty(&context->killed_trees))
|
||||
audit_kill_trees(context);
|
||||
|
||||
/* We are called either by do_exit() or the fork() error handling code;
|
||||
* in the former case tsk == current and in the latter tsk is a
|
||||
* random task_struct that doesn't doesn't have any meaningful data we
|
||||
@ -1460,9 +1586,6 @@ void __audit_free(struct task_struct *tsk)
|
||||
audit_log_exit();
|
||||
}
|
||||
|
||||
if (!list_empty(&context->killed_trees))
|
||||
audit_kill_trees(&context->killed_trees);
|
||||
|
||||
audit_set_context(tsk, NULL);
|
||||
audit_free_context(context);
|
||||
}
|
||||
@ -1537,6 +1660,9 @@ void __audit_syscall_exit(int success, long return_code)
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (!list_empty(&context->killed_trees))
|
||||
audit_kill_trees(context);
|
||||
|
||||
if (!context->dummy && context->in_syscall) {
|
||||
if (success)
|
||||
context->return_valid = AUDITSC_SUCCESS;
|
||||
@ -1571,9 +1697,6 @@ void __audit_syscall_exit(int success, long return_code)
|
||||
context->in_syscall = 0;
|
||||
context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
|
||||
|
||||
if (!list_empty(&context->killed_trees))
|
||||
audit_kill_trees(&context->killed_trees);
|
||||
|
||||
audit_free_names(context);
|
||||
unroll_tree_refs(context, NULL, 0);
|
||||
audit_free_aux(context);
|
||||
@ -1750,6 +1873,47 @@ void __audit_getname(struct filename *name)
|
||||
get_fs_pwd(current->fs, &context->pwd);
|
||||
}
|
||||
|
||||
static inline int audit_copy_fcaps(struct audit_names *name,
|
||||
const struct dentry *dentry)
|
||||
{
|
||||
struct cpu_vfs_cap_data caps;
|
||||
int rc;
|
||||
|
||||
if (!dentry)
|
||||
return 0;
|
||||
|
||||
rc = get_vfs_caps_from_disk(dentry, &caps);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
name->fcap.permitted = caps.permitted;
|
||||
name->fcap.inheritable = caps.inheritable;
|
||||
name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
|
||||
name->fcap.rootid = caps.rootid;
|
||||
name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >>
|
||||
VFS_CAP_REVISION_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy inode data into an audit_names. */
|
||||
void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
|
||||
struct inode *inode, unsigned int flags)
|
||||
{
|
||||
name->ino = inode->i_ino;
|
||||
name->dev = inode->i_sb->s_dev;
|
||||
name->mode = inode->i_mode;
|
||||
name->uid = inode->i_uid;
|
||||
name->gid = inode->i_gid;
|
||||
name->rdev = inode->i_rdev;
|
||||
security_inode_getsecid(inode, &name->osid);
|
||||
if (flags & AUDIT_INODE_NOEVAL) {
|
||||
name->fcap_ver = -1;
|
||||
return;
|
||||
}
|
||||
audit_copy_fcaps(name, dentry);
|
||||
}
|
||||
|
||||
/**
|
||||
* __audit_inode - store the inode and device from a lookup
|
||||
* @name: name being audited
|
||||
@ -1763,10 +1927,31 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct audit_names *n;
|
||||
bool parent = flags & AUDIT_INODE_PARENT;
|
||||
struct audit_entry *e;
|
||||
struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
|
||||
int i;
|
||||
|
||||
if (!context->in_syscall)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
if (!list_empty(list)) {
|
||||
list_for_each_entry_rcu(e, list, list) {
|
||||
for (i = 0; i < e->rule.field_count; i++) {
|
||||
struct audit_field *f = &e->rule.fields[i];
|
||||
|
||||
if (f->type == AUDIT_FSTYPE
|
||||
&& audit_comparator(inode->i_sb->s_magic,
|
||||
f->op, f->val)
|
||||
&& e->rule.action == AUDIT_NEVER) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!name)
|
||||
goto out_alloc;
|
||||
|
||||
@ -1832,7 +2017,7 @@ out:
|
||||
n->type = AUDIT_TYPE_NORMAL;
|
||||
}
|
||||
handle_path(dentry);
|
||||
audit_copy_inode(n, dentry, inode);
|
||||
audit_copy_inode(n, dentry, inode, flags & AUDIT_INODE_NOEVAL);
|
||||
}
|
||||
|
||||
void __audit_file(const struct file *file)
|
||||
@ -1875,14 +2060,12 @@ void __audit_inode_child(struct inode *parent,
|
||||
for (i = 0; i < e->rule.field_count; i++) {
|
||||
struct audit_field *f = &e->rule.fields[i];
|
||||
|
||||
if (f->type == AUDIT_FSTYPE) {
|
||||
if (audit_comparator(parent->i_sb->s_magic,
|
||||
f->op, f->val)) {
|
||||
if (e->rule.action == AUDIT_NEVER) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (f->type == AUDIT_FSTYPE
|
||||
&& audit_comparator(parent->i_sb->s_magic,
|
||||
f->op, f->val)
|
||||
&& e->rule.action == AUDIT_NEVER) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1933,7 +2116,7 @@ void __audit_inode_child(struct inode *parent,
|
||||
n = audit_alloc_name(context, AUDIT_TYPE_PARENT);
|
||||
if (!n)
|
||||
return;
|
||||
audit_copy_inode(n, NULL, parent);
|
||||
audit_copy_inode(n, NULL, parent, 0);
|
||||
}
|
||||
|
||||
if (!found_child) {
|
||||
@ -1952,7 +2135,7 @@ void __audit_inode_child(struct inode *parent,
|
||||
}
|
||||
|
||||
if (inode)
|
||||
audit_copy_inode(found_child, dentry, inode);
|
||||
audit_copy_inode(found_child, dentry, inode, 0);
|
||||
else
|
||||
found_child->ino = AUDIT_INO_UNSET;
|
||||
}
|
||||
@ -1983,90 +2166,6 @@ int auditsc_get_stamp(struct audit_context *ctx,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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, oldloginuid, loginuid;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!audit_enabled)
|
||||
return;
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
|
||||
if (!ab)
|
||||
return;
|
||||
|
||||
uid = from_kuid(&init_user_ns, task_uid(current));
|
||||
oldloginuid = from_kuid(&init_user_ns, koldloginuid);
|
||||
loginuid = from_kuid(&init_user_ns, kloginuid),
|
||||
tty = audit_get_tty();
|
||||
|
||||
audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
|
||||
audit_log_task_context(ab);
|
||||
audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
|
||||
oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
|
||||
oldsessionid, sessionid, !rc);
|
||||
audit_put_tty(tty);
|
||||
audit_log_end(ab);
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_set_loginuid - set current task's audit_context loginuid
|
||||
* @loginuid: loginuid value
|
||||
*
|
||||
* Returns 0.
|
||||
*
|
||||
* Called (set) from fs/proc/base.c::proc_loginuid_write().
|
||||
*/
|
||||
int audit_set_loginuid(kuid_t loginuid)
|
||||
{
|
||||
unsigned int oldsessionid, sessionid = AUDIT_SID_UNSET;
|
||||
kuid_t oldloginuid;
|
||||
int rc;
|
||||
|
||||
oldloginuid = audit_get_loginuid(current);
|
||||
oldsessionid = audit_get_sessionid(current);
|
||||
|
||||
rc = audit_set_loginuid_perm(loginuid);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* are we setting or clearing? */
|
||||
if (uid_valid(loginuid)) {
|
||||
sessionid = (unsigned int)atomic_inc_return(&session_id);
|
||||
if (unlikely(sessionid == AUDIT_SID_UNSET))
|
||||
sessionid = (unsigned int)atomic_inc_return(&session_id);
|
||||
}
|
||||
|
||||
current->sessionid = sessionid;
|
||||
current->loginuid = loginuid;
|
||||
out:
|
||||
audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* __audit_mq_open - record audit data for a POSIX MQ open
|
||||
* @oflag: open flag
|
||||
@ -2355,6 +2454,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
|
||||
ax->fcap.permitted = vcaps.permitted;
|
||||
ax->fcap.inheritable = vcaps.inheritable;
|
||||
ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
|
||||
ax->fcap.rootid = vcaps.rootid;
|
||||
ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
|
||||
|
||||
ax->old_pcap.permitted = old->cap_permitted;
|
||||
|
@ -225,8 +225,7 @@ int aa_audit_rule_known(struct audit_krule *rule)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
|
||||
struct audit_context *actx)
|
||||
int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
|
||||
{
|
||||
struct aa_audit_rule *rule = vrule;
|
||||
struct aa_label *label;
|
||||
|
@ -192,7 +192,6 @@ static inline int complain_error(int error)
|
||||
void aa_audit_rule_free(void *vrule);
|
||||
int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
|
||||
int aa_audit_rule_known(struct audit_krule *rule);
|
||||
int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
|
||||
struct audit_context *actx);
|
||||
int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
|
||||
|
||||
#endif /* __AA_AUDIT_H */
|
||||
|
@ -642,6 +642,8 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
|
||||
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
||||
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
||||
|
||||
cpu_caps->rootid = rootkuid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -307,8 +307,7 @@ static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr,
|
||||
}
|
||||
|
||||
static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
|
||||
void *lsmrule,
|
||||
struct audit_context *actx)
|
||||
void *lsmrule)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -340,8 +340,7 @@ retry:
|
||||
rc = security_filter_rule_match(osid,
|
||||
rule->lsm[i].type,
|
||||
Audit_equal,
|
||||
rule->lsm[i].rule,
|
||||
NULL);
|
||||
rule->lsm[i].rule);
|
||||
break;
|
||||
case LSM_SUBJ_USER:
|
||||
case LSM_SUBJ_ROLE:
|
||||
@ -349,8 +348,7 @@ retry:
|
||||
rc = security_filter_rule_match(secid,
|
||||
rule->lsm[i].type,
|
||||
Audit_equal,
|
||||
rule->lsm[i].rule,
|
||||
NULL);
|
||||
rule->lsm[i].rule);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2302,11 +2302,9 @@ void security_audit_rule_free(void *lsmrule)
|
||||
call_void_hook(audit_rule_free, lsmrule);
|
||||
}
|
||||
|
||||
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
|
||||
struct audit_context *actx)
|
||||
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,
|
||||
actx);
|
||||
return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
|
||||
}
|
||||
#endif /* CONFIG_AUDIT */
|
||||
|
||||
|
@ -43,13 +43,11 @@ void selinux_audit_rule_free(void *rule);
|
||||
* @field: the field this rule refers to
|
||||
* @op: the operater the rule uses
|
||||
* @rule: pointer to the audit rule to check against
|
||||
* @actx: the audit context (can be NULL) associated with the check
|
||||
*
|
||||
* Returns 1 if the context id matches the rule, 0 if it does not, and
|
||||
* -errno on failure.
|
||||
*/
|
||||
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule,
|
||||
struct audit_context *actx);
|
||||
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
|
||||
|
||||
/**
|
||||
* selinux_audit_rule_known - check to see if rule contains selinux fields.
|
||||
|
@ -3402,8 +3402,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
|
||||
struct audit_context *actx)
|
||||
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
|
||||
{
|
||||
struct selinux_state *state = &selinux_state;
|
||||
struct context *ctxt;
|
||||
|
@ -4295,13 +4295,11 @@ static int smack_audit_rule_known(struct audit_krule *krule)
|
||||
* @field: audit rule flags given from user-space
|
||||
* @op: required testing operator
|
||||
* @vrule: smack internal rule presentation
|
||||
* @actx: audit context associated with the check
|
||||
*
|
||||
* The core Audit hook. It's used to take the decision of
|
||||
* whether to audit or not to audit a given object.
|
||||
*/
|
||||
static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
|
||||
struct audit_context *actx)
|
||||
static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
|
||||
{
|
||||
struct smack_known *skp;
|
||||
char *rule = vrule;
|
||||
|
Loading…
Reference in New Issue
Block a user