You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'audit.b3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current
* 'audit.b3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current: (22 commits) [PATCH] fix audit_init failure path [PATCH] EXPORT_SYMBOL patch for audit_log, audit_log_start, audit_log_end and audit_format [PATCH] sem2mutex: audit_netlink_sem [PATCH] simplify audit_free() locking [PATCH] Fix audit operators [PATCH] promiscuous mode [PATCH] Add tty to syscall audit records [PATCH] add/remove rule update [PATCH] audit string fields interface + consumer [PATCH] SE Linux audit events [PATCH] Minor cosmetic cleanups to the code moved into auditfilter.c [PATCH] Fix audit record filtering with !CONFIG_AUDITSYSCALL [PATCH] Fix IA64 success/failure indication in syscall auditing. [PATCH] Miscellaneous bug and warning fixes [PATCH] Capture selinux subject/object context information. [PATCH] Exclude messages by message type [PATCH] Collect more inode information during syscall processing. [PATCH] Pass dentry, not just name, in fsnotify creation hooks. [PATCH] Define new range of userspace messages. [PATCH] Filter rule comparators ... Fixed trivial conflict in security/selinux/hooks.c
This commit is contained in:
+10
-2
@@ -43,6 +43,7 @@
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
@@ -252,6 +253,7 @@ out:
|
||||
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
|
||||
{
|
||||
struct tss_struct *tss;
|
||||
long eax;
|
||||
/*
|
||||
* make sure the vm86() system call doesn't try to do anything silly
|
||||
*/
|
||||
@@ -305,13 +307,19 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
|
||||
tsk->thread.screen_bitmap = info->screen_bitmap;
|
||||
if (info->flags & VM86_SCREEN_BITMAP)
|
||||
mark_screen_rdonly(tsk->mm);
|
||||
__asm__ __volatile__("xorl %eax,%eax; movl %eax,%fs; movl %eax,%gs\n\t");
|
||||
__asm__ __volatile__("movl %%eax, %0\n" :"=r"(eax));
|
||||
|
||||
/*call audit_syscall_exit since we do not exit via the normal paths */
|
||||
if (unlikely(current->audit_context))
|
||||
audit_syscall_exit(current, AUDITSC_RESULT(eax), eax);
|
||||
|
||||
__asm__ __volatile__(
|
||||
"xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t"
|
||||
"movl %0,%%esp\n\t"
|
||||
"movl %1,%%ebp\n\t"
|
||||
"jmp resume_userspace"
|
||||
: /* no outputs */
|
||||
:"r" (&info->regs), "r" (task_thread_info(tsk)) : "ax");
|
||||
:"r" (&info->regs), "r" (task_thread_info(tsk)));
|
||||
/* we never return here */
|
||||
}
|
||||
|
||||
|
||||
@@ -1656,8 +1656,14 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6, long arg7,
|
||||
struct pt_regs regs)
|
||||
{
|
||||
if (unlikely(current->audit_context))
|
||||
audit_syscall_exit(current, AUDITSC_RESULT(regs.r10), regs.r8);
|
||||
if (unlikely(current->audit_context)) {
|
||||
int success = AUDITSC_RESULT(regs.r10);
|
||||
long result = regs.r8;
|
||||
|
||||
if (success != AUDITSC_SUCCESS)
|
||||
result = -result;
|
||||
audit_syscall_exit(current, success, result);
|
||||
}
|
||||
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE)
|
||||
&& (current->ptrace & PT_PTRACED))
|
||||
|
||||
+6
-5
@@ -1353,6 +1353,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
|
||||
return -ENOENT;
|
||||
|
||||
BUG_ON(victim->d_parent->d_inode != dir);
|
||||
audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino);
|
||||
|
||||
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
|
||||
if (error)
|
||||
@@ -1472,7 +1473,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->create(dir, dentry, mode, nd);
|
||||
if (!error)
|
||||
fsnotify_create(dir, dentry->d_name.name);
|
||||
fsnotify_create(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1799,7 +1800,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->mknod(dir, dentry, mode, dev);
|
||||
if (!error)
|
||||
fsnotify_create(dir, dentry->d_name.name);
|
||||
fsnotify_create(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1876,7 +1877,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->mkdir(dir, dentry, mode);
|
||||
if (!error)
|
||||
fsnotify_mkdir(dir, dentry->d_name.name);
|
||||
fsnotify_mkdir(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -2139,7 +2140,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i
|
||||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->symlink(dir, dentry, oldname);
|
||||
if (!error)
|
||||
fsnotify_create(dir, dentry->d_name.name);
|
||||
fsnotify_create(dir, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -2216,7 +2217,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
|
||||
error = dir->i_op->link(old_dentry, dir, new_dentry);
|
||||
mutex_unlock(&old_dentry->d_inode->i_mutex);
|
||||
if (!error)
|
||||
fsnotify_create(dir, new_dentry->d_name.name);
|
||||
fsnotify_create(dir, new_dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
#include <asm/unistd.h>
|
||||
|
||||
@@ -626,6 +627,8 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
|
||||
dentry = file->f_dentry;
|
||||
inode = dentry->d_inode;
|
||||
|
||||
audit_inode(NULL, inode, 0);
|
||||
|
||||
err = -EROFS;
|
||||
if (IS_RDONLY(inode))
|
||||
goto out_putf;
|
||||
@@ -775,7 +778,10 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
|
||||
|
||||
file = fget(fd);
|
||||
if (file) {
|
||||
error = chown_common(file->f_dentry, user, group);
|
||||
struct dentry * dentry;
|
||||
dentry = file->f_dentry;
|
||||
audit_inode(NULL, dentry->d_inode, 0);
|
||||
error = chown_common(dentry, user, group);
|
||||
fput(file);
|
||||
}
|
||||
return error;
|
||||
|
||||
+9
-2
@@ -17,6 +17,7 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/audit.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
||||
@@ -234,12 +235,15 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
struct file *f;
|
||||
struct dentry *dentry;
|
||||
int error = -EBADF;
|
||||
|
||||
f = fget(fd);
|
||||
if (!f)
|
||||
return error;
|
||||
error = setxattr(f->f_dentry, name, value, size, flags);
|
||||
dentry = f->f_dentry;
|
||||
audit_inode(NULL, dentry->d_inode, 0);
|
||||
error = setxattr(dentry, name, value, size, flags);
|
||||
fput(f);
|
||||
return error;
|
||||
}
|
||||
@@ -458,12 +462,15 @@ asmlinkage long
|
||||
sys_fremovexattr(int fd, char __user *name)
|
||||
{
|
||||
struct file *f;
|
||||
struct dentry *dentry;
|
||||
int error = -EBADF;
|
||||
|
||||
f = fget(fd);
|
||||
if (!f)
|
||||
return error;
|
||||
error = removexattr(f->f_dentry, name);
|
||||
dentry = f->f_dentry;
|
||||
audit_inode(NULL, dentry->d_inode, 0);
|
||||
error = removexattr(dentry, name);
|
||||
fput(f);
|
||||
return error;
|
||||
}
|
||||
|
||||
+107
-23
@@ -33,27 +33,42 @@
|
||||
* 1200 - 1299 messages internal to the audit daemon
|
||||
* 1300 - 1399 audit event messages
|
||||
* 1400 - 1499 SE Linux use
|
||||
* 1500 - 1999 future use
|
||||
* 2000 is for otherwise unclassified kernel audit messages
|
||||
* 1500 - 1599 kernel LSPP events
|
||||
* 1600 - 1699 kernel crypto events
|
||||
* 1700 - 1799 kernel anomaly records
|
||||
* 1800 - 1999 future kernel use (maybe integrity labels and related events)
|
||||
* 2000 is for otherwise unclassified kernel audit messages (legacy)
|
||||
* 2001 - 2099 unused (kernel)
|
||||
* 2100 - 2199 user space anomaly records
|
||||
* 2200 - 2299 user space actions taken in response to anomalies
|
||||
* 2300 - 2399 user space generated LSPP events
|
||||
* 2400 - 2499 user space crypto events
|
||||
* 2500 - 2999 future user space (maybe integrity labels and related events)
|
||||
*
|
||||
* Messages from 1000-1199 are bi-directional. 1200-1299 are exclusively user
|
||||
* space. Anything over that is kernel --> user space communication.
|
||||
* Messages from 1000-1199 are bi-directional. 1200-1299 & 2100 - 2999 are
|
||||
* exclusively user space. 1300-2099 is kernel --> user space
|
||||
* communication.
|
||||
*/
|
||||
#define AUDIT_GET 1000 /* Get status */
|
||||
#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */
|
||||
#define AUDIT_LIST 1002 /* List syscall filtering rules */
|
||||
#define AUDIT_ADD 1003 /* Add syscall filtering rule */
|
||||
#define AUDIT_DEL 1004 /* Delete syscall filtering rule */
|
||||
#define AUDIT_LIST 1002 /* List syscall rules -- deprecated */
|
||||
#define AUDIT_ADD 1003 /* Add syscall rule -- deprecated */
|
||||
#define AUDIT_DEL 1004 /* Delete syscall rule -- deprecated */
|
||||
#define AUDIT_USER 1005 /* Message from userspace -- deprecated */
|
||||
#define AUDIT_LOGIN 1006 /* Define the login id and information */
|
||||
#define AUDIT_WATCH_INS 1007 /* Insert file/dir watch entry */
|
||||
#define AUDIT_WATCH_REM 1008 /* Remove file/dir watch entry */
|
||||
#define AUDIT_WATCH_LIST 1009 /* List all file/dir watches */
|
||||
#define AUDIT_SIGNAL_INFO 1010 /* Get info about sender of signal to auditd */
|
||||
#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
|
||||
#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
|
||||
#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
|
||||
|
||||
#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */
|
||||
#define AUDIT_USER_AVC 1107 /* We filter this differently */
|
||||
#define AUDIT_LAST_USER_MSG 1199
|
||||
#define AUDIT_FIRST_USER_MSG2 2100 /* More user space messages */
|
||||
#define AUDIT_LAST_USER_MSG2 2999
|
||||
|
||||
#define AUDIT_DAEMON_START 1200 /* Daemon startup record */
|
||||
#define AUDIT_DAEMON_END 1201 /* Daemon normal stop record */
|
||||
@@ -72,6 +87,13 @@
|
||||
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
|
||||
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
|
||||
#define AUDIT_AVC_PATH 1402 /* dentry, vfsmount pair from avc */
|
||||
#define AUDIT_MAC_POLICY_LOAD 1403 /* Policy file load */
|
||||
#define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */
|
||||
#define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */
|
||||
|
||||
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
|
||||
#define AUDIT_LAST_KERN_ANOM_MSG 1799
|
||||
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
|
||||
|
||||
#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
|
||||
|
||||
@@ -81,8 +103,9 @@
|
||||
#define AUDIT_FILTER_ENTRY 0x02 /* Apply rule at syscall entry */
|
||||
#define AUDIT_FILTER_WATCH 0x03 /* Apply rule to file system watches */
|
||||
#define AUDIT_FILTER_EXIT 0x04 /* Apply rule at syscall exit */
|
||||
#define AUDIT_FILTER_TYPE 0x05 /* Apply rule at audit_log_start */
|
||||
|
||||
#define AUDIT_NR_FILTERS 5
|
||||
#define AUDIT_NR_FILTERS 6
|
||||
|
||||
#define AUDIT_FILTER_PREPEND 0x10 /* Prepend to front of list */
|
||||
|
||||
@@ -98,6 +121,13 @@
|
||||
#define AUDIT_WORD(nr) ((__u32)((nr)/32))
|
||||
#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32))
|
||||
|
||||
/* This bitmask is used to validate user input. It represents all bits that
|
||||
* are currently used in an audit field constant understood by the kernel.
|
||||
* If you are adding a new #define AUDIT_<whatever>, please ensure that
|
||||
* AUDIT_UNUSED_BITS is updated if need be. */
|
||||
#define AUDIT_UNUSED_BITS 0x0FFFFC00
|
||||
|
||||
|
||||
/* Rule fields */
|
||||
/* These are useful when checking the
|
||||
* task structure at task creation time
|
||||
@@ -114,6 +144,7 @@
|
||||
#define AUDIT_LOGINUID 9
|
||||
#define AUDIT_PERS 10
|
||||
#define AUDIT_ARCH 11
|
||||
#define AUDIT_MSGTYPE 12
|
||||
|
||||
/* These are ONLY useful when checking
|
||||
* at syscall exit time (AUDIT_AT_EXIT). */
|
||||
@@ -128,8 +159,28 @@
|
||||
#define AUDIT_ARG2 (AUDIT_ARG0+2)
|
||||
#define AUDIT_ARG3 (AUDIT_ARG0+3)
|
||||
|
||||
#define AUDIT_NEGATE 0x80000000
|
||||
#define AUDIT_NEGATE 0x80000000
|
||||
|
||||
/* These are the supported operators.
|
||||
* 4 2 1
|
||||
* = > <
|
||||
* -------
|
||||
* 0 0 0 0 nonsense
|
||||
* 0 0 1 1 <
|
||||
* 0 1 0 2 >
|
||||
* 0 1 1 3 !=
|
||||
* 1 0 0 4 =
|
||||
* 1 0 1 5 <=
|
||||
* 1 1 0 6 >=
|
||||
* 1 1 1 7 all operators
|
||||
*/
|
||||
#define AUDIT_LESS_THAN 0x10000000
|
||||
#define AUDIT_GREATER_THAN 0x20000000
|
||||
#define AUDIT_NOT_EQUAL 0x30000000
|
||||
#define AUDIT_EQUAL 0x40000000
|
||||
#define AUDIT_LESS_THAN_OR_EQUAL (AUDIT_LESS_THAN|AUDIT_EQUAL)
|
||||
#define AUDIT_GREATER_THAN_OR_EQUAL (AUDIT_GREATER_THAN|AUDIT_EQUAL)
|
||||
#define AUDIT_OPERATORS (AUDIT_EQUAL|AUDIT_NOT_EQUAL)
|
||||
|
||||
/* Status symbols */
|
||||
/* Mask values */
|
||||
@@ -186,6 +237,26 @@ struct audit_status {
|
||||
__u32 backlog; /* messages waiting in queue */
|
||||
};
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
struct audit_rule_data {
|
||||
__u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
|
||||
__u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
|
||||
__u32 field_count;
|
||||
__u32 mask[AUDIT_BITMASK_SIZE]; /* syscall(s) affected */
|
||||
__u32 fields[AUDIT_MAX_FIELDS];
|
||||
__u32 values[AUDIT_MAX_FIELDS];
|
||||
__u32 fieldflags[AUDIT_MAX_FIELDS];
|
||||
__u32 buflen; /* total length of string fields */
|
||||
char buf[0]; /* string fields buffer */
|
||||
};
|
||||
|
||||
/* audit_rule is supported to maintain backward compatibility with
|
||||
* userspace. It supports integer fields only and corresponds to
|
||||
* AUDIT_ADD, AUDIT_DEL and AUDIT_LIST requests.
|
||||
*/
|
||||
struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
|
||||
__u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */
|
||||
__u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */
|
||||
@@ -222,22 +293,33 @@ extern void audit_syscall_entry(struct task_struct *task, int arch,
|
||||
extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
|
||||
extern void audit_getname(const char *name);
|
||||
extern void audit_putname(const char *name);
|
||||
extern void audit_inode(const char *name, const struct inode *inode, unsigned flags);
|
||||
extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags);
|
||||
extern void __audit_inode_child(const char *dname, const struct inode *inode,
|
||||
unsigned long pino);
|
||||
static inline void audit_inode(const char *name, const struct inode *inode,
|
||||
unsigned flags) {
|
||||
if (unlikely(current->audit_context))
|
||||
__audit_inode(name, inode, flags);
|
||||
}
|
||||
static inline void audit_inode_child(const char *dname,
|
||||
const struct inode *inode,
|
||||
unsigned long pino) {
|
||||
if (unlikely(current->audit_context))
|
||||
__audit_inode_child(dname, inode, pino);
|
||||
}
|
||||
|
||||
/* Private API (for audit.c only) */
|
||||
extern int audit_receive_filter(int type, int pid, int uid, int seq,
|
||||
void *data, uid_t loginuid);
|
||||
extern unsigned int audit_serial(void);
|
||||
extern void auditsc_get_stamp(struct audit_context *ctx,
|
||||
struct timespec *t, unsigned int *serial);
|
||||
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
|
||||
extern uid_t audit_get_loginuid(struct audit_context *ctx);
|
||||
extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
|
||||
extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
|
||||
extern int audit_socketcall(int nargs, unsigned long *args);
|
||||
extern int audit_sockaddr(int len, void *addr);
|
||||
extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
|
||||
extern void audit_signal_info(int sig, struct task_struct *t);
|
||||
extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
|
||||
extern int audit_set_macxattr(const char *name);
|
||||
#else
|
||||
#define audit_alloc(t) ({ 0; })
|
||||
#define audit_free(t) do { ; } while (0)
|
||||
@@ -245,16 +327,18 @@ extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
|
||||
#define audit_syscall_exit(t,f,r) do { ; } while (0)
|
||||
#define audit_getname(n) do { ; } while (0)
|
||||
#define audit_putname(n) do { ; } while (0)
|
||||
#define __audit_inode(n,i,f) do { ; } while (0)
|
||||
#define __audit_inode_child(d,i,p) do { ; } while (0)
|
||||
#define audit_inode(n,i,f) do { ; } while (0)
|
||||
#define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; })
|
||||
#define audit_inode_child(d,i,p) do { ; } while (0)
|
||||
#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
|
||||
#define audit_get_loginuid(c) ({ -1; })
|
||||
#define audit_ipc_perms(q,u,g,m) ({ 0; })
|
||||
#define audit_ipc_perms(q,u,g,m,i) ({ 0; })
|
||||
#define audit_socketcall(n,a) ({ 0; })
|
||||
#define audit_sockaddr(len, addr) ({ 0; })
|
||||
#define audit_avc_path(dentry, mnt) ({ 0; })
|
||||
#define audit_signal_info(s,t) do { ; } while (0)
|
||||
#define audit_filter_user(cb,t) ({ 1; })
|
||||
#define audit_set_macxattr(n) do { ; } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AUDIT
|
||||
@@ -278,12 +362,11 @@ extern void audit_log_d_path(struct audit_buffer *ab,
|
||||
const char *prefix,
|
||||
struct dentry *dentry,
|
||||
struct vfsmount *vfsmnt);
|
||||
/* Private API (for auditsc.c only) */
|
||||
extern void audit_send_reply(int pid, int seq, int type,
|
||||
int done, int multi,
|
||||
void *payload, int size);
|
||||
extern void audit_log_lost(const char *message);
|
||||
extern struct semaphore audit_netlink_sem;
|
||||
/* Private API (for audit.c only) */
|
||||
extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
|
||||
extern int audit_filter_type(int type);
|
||||
extern int audit_receive_filter(int type, int pid, int uid, int seq,
|
||||
void *data, size_t datasz, uid_t loginuid);
|
||||
#else
|
||||
#define audit_log(c,g,t,f,...) do { ; } while (0)
|
||||
#define audit_log_start(c,g,t) ({ NULL; })
|
||||
@@ -293,6 +376,7 @@ extern struct semaphore audit_netlink_sem;
|
||||
#define audit_log_hex(a,b,l) do { ; } while (0)
|
||||
#define audit_log_untrustedstring(a,s) do { ; } while (0)
|
||||
#define audit_log_d_path(b,p,d,v) do { ; } while (0)
|
||||
#define audit_panic(m) do { ; } while (0)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/inotify.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
/*
|
||||
* fsnotify_d_instantiate - instantiate a dentry for inode
|
||||
@@ -64,6 +65,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
|
||||
if (source) {
|
||||
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL);
|
||||
}
|
||||
audit_inode_child(old_name, source, old_dir->i_ino);
|
||||
audit_inode_child(new_name, target, new_dir->i_ino);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -89,19 +92,22 @@ static inline void fsnotify_inoderemove(struct inode *inode)
|
||||
/*
|
||||
* fsnotify_create - 'name' was linked in
|
||||
*/
|
||||
static inline void fsnotify_create(struct inode *inode, const char *name)
|
||||
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
|
||||
{
|
||||
inode_dir_notify(inode, DN_CREATE);
|
||||
inotify_inode_queue_event(inode, IN_CREATE, 0, name);
|
||||
inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name);
|
||||
audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* fsnotify_mkdir - directory 'name' was created
|
||||
*/
|
||||
static inline void fsnotify_mkdir(struct inode *inode, const char *name)
|
||||
static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
|
||||
{
|
||||
inode_dir_notify(inode, DN_CREATE);
|
||||
inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, name);
|
||||
inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0,
|
||||
dentry->d_name.name);
|
||||
audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -869,6 +869,11 @@ struct swap_info_struct;
|
||||
* @ipcp contains the kernel IPC permission structure
|
||||
* @flag contains the desired (requested) permission set
|
||||
* Return 0 if permission is granted.
|
||||
* @ipc_getsecurity:
|
||||
* Copy the security label associated with the ipc object into
|
||||
* @buffer. @buffer may be NULL to request the size of the buffer
|
||||
* required. @size indicates the size of @buffer in bytes. Return
|
||||
* number of bytes used/required on success.
|
||||
*
|
||||
* Security hooks for individual messages held in System V IPC message queues
|
||||
* @msg_msg_alloc_security:
|
||||
@@ -1168,7 +1173,8 @@ struct security_operations {
|
||||
int (*inode_getxattr) (struct dentry *dentry, char *name);
|
||||
int (*inode_listxattr) (struct dentry *dentry);
|
||||
int (*inode_removexattr) (struct dentry *dentry, char *name);
|
||||
int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size, int err);
|
||||
const char *(*inode_xattr_getsuffix) (void);
|
||||
int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
|
||||
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
|
||||
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
|
||||
|
||||
@@ -1217,6 +1223,7 @@ struct security_operations {
|
||||
void (*task_to_inode)(struct task_struct *p, struct inode *inode);
|
||||
|
||||
int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
|
||||
int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size);
|
||||
|
||||
int (*msg_msg_alloc_security) (struct msg_msg * msg);
|
||||
void (*msg_msg_free_security) (struct msg_msg * msg);
|
||||
@@ -1680,7 +1687,12 @@ static inline int security_inode_removexattr (struct dentry *dentry, char *name)
|
||||
return security_ops->inode_removexattr (dentry, name);
|
||||
}
|
||||
|
||||
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
static inline const char *security_inode_xattr_getsuffix(void)
|
||||
{
|
||||
return security_ops->inode_xattr_getsuffix();
|
||||
}
|
||||
|
||||
static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
{
|
||||
if (unlikely (IS_PRIVATE (inode)))
|
||||
return 0;
|
||||
@@ -1875,6 +1887,11 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
|
||||
return security_ops->ipc_permission (ipcp, flag);
|
||||
}
|
||||
|
||||
static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
|
||||
{
|
||||
return security_ops->ipc_getsecurity(ipcp, buffer, size);
|
||||
}
|
||||
|
||||
static inline int security_msg_msg_alloc (struct msg_msg * msg)
|
||||
{
|
||||
return security_ops->msg_msg_alloc_security (msg);
|
||||
@@ -2327,7 +2344,12 @@ static inline int security_inode_removexattr (struct dentry *dentry, char *name)
|
||||
return cap_inode_removexattr(dentry, name);
|
||||
}
|
||||
|
||||
static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
static inline const char *security_inode_xattr_getsuffix (void)
|
||||
{
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -2510,6 +2532,11 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int security_msg_msg_alloc (struct msg_msg * msg)
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -428,8 +428,6 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
|
||||
return -EFAULT;
|
||||
if (copy_msqid_from_user (&setbuf, buf, version))
|
||||
return -EFAULT;
|
||||
if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
|
||||
return err;
|
||||
break;
|
||||
case IPC_RMID:
|
||||
break;
|
||||
@@ -460,6 +458,9 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
|
||||
switch (cmd) {
|
||||
case IPC_SET:
|
||||
{
|
||||
if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
|
||||
goto out_unlock_up;
|
||||
|
||||
err = -EPERM;
|
||||
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
|
||||
goto out_unlock_up;
|
||||
|
||||
@@ -809,8 +809,6 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
|
||||
if(cmd == IPC_SET) {
|
||||
if(copy_semid_from_user (&setbuf, arg.buf, version))
|
||||
return -EFAULT;
|
||||
if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
|
||||
return err;
|
||||
}
|
||||
sma = sem_lock(semid);
|
||||
if(sma==NULL)
|
||||
@@ -821,7 +819,6 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
|
||||
goto out_unlock;
|
||||
}
|
||||
ipcp = &sma->sem_perm;
|
||||
|
||||
if (current->euid != ipcp->cuid &&
|
||||
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
|
||||
err=-EPERM;
|
||||
@@ -838,6 +835,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
|
||||
err = 0;
|
||||
break;
|
||||
case IPC_SET:
|
||||
if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
|
||||
goto out_unlock;
|
||||
ipcp->uid = setbuf.uid;
|
||||
ipcp->gid = setbuf.gid;
|
||||
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
|
||||
|
||||
@@ -620,13 +620,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
|
||||
return err;
|
||||
down(&shm_ids.sem);
|
||||
shp = shm_lock(shmid);
|
||||
err=-EINVAL;
|
||||
if(shp==NULL)
|
||||
goto out_up;
|
||||
if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
|
||||
goto out_unlock_up;
|
||||
err = shm_checkid(shp,shmid);
|
||||
if(err)
|
||||
goto out_unlock_up;
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ obj-$(CONFIG_COMPAT) += compat.o
|
||||
obj-$(CONFIG_CPUSETS) += cpuset.o
|
||||
obj-$(CONFIG_IKCONFIG) += configs.o
|
||||
obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
|
||||
obj-$(CONFIG_AUDIT) += audit.o
|
||||
obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
|
||||
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
obj-$(CONFIG_SYSFS) += ksysfs.o
|
||||
|
||||
+140
-35
@@ -52,6 +52,7 @@
|
||||
#include <linux/audit.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
@@ -72,7 +73,7 @@ static int audit_failure = AUDIT_FAIL_PRINTK;
|
||||
* contains the (non-zero) pid. */
|
||||
int audit_pid;
|
||||
|
||||
/* If audit_limit is non-zero, limit the rate of sending audit records
|
||||
/* If audit_rate_limit is non-zero, limit the rate of sending audit records
|
||||
* to that number per second. This prevents DoS attacks, but results in
|
||||
* audit records being dropped. */
|
||||
static int audit_rate_limit;
|
||||
@@ -102,7 +103,7 @@ static struct sock *audit_sock;
|
||||
* than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
|
||||
* being placed on the freelist). */
|
||||
static DEFINE_SPINLOCK(audit_freelist_lock);
|
||||
static int audit_freelist_count = 0;
|
||||
static int audit_freelist_count;
|
||||
static LIST_HEAD(audit_freelist);
|
||||
|
||||
static struct sk_buff_head audit_skb_queue;
|
||||
@@ -113,7 +114,7 @@ static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
|
||||
/* The netlink socket is only to be read by 1 CPU, which lets us assume
|
||||
* that list additions and deletions never happen simultaneously in
|
||||
* auditsc.c */
|
||||
DECLARE_MUTEX(audit_netlink_sem);
|
||||
DEFINE_MUTEX(audit_netlink_mutex);
|
||||
|
||||
/* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
|
||||
* audit records. Since printk uses a 1024 byte buffer, this buffer
|
||||
@@ -142,7 +143,7 @@ static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
|
||||
nlh->nlmsg_pid = pid;
|
||||
}
|
||||
|
||||
static void audit_panic(const char *message)
|
||||
void audit_panic(const char *message)
|
||||
{
|
||||
switch (audit_failure)
|
||||
{
|
||||
@@ -186,8 +187,14 @@ static inline int audit_rate_check(void)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Emit at least 1 message per second, even if audit_rate_check is
|
||||
* throttling. */
|
||||
/**
|
||||
* audit_log_lost - conditionally log lost audit message event
|
||||
* @message: the message stating reason for lost audit message
|
||||
*
|
||||
* Emit at least 1 message per second, even if audit_rate_check is
|
||||
* throttling.
|
||||
* Always increment the lost messages counter.
|
||||
*/
|
||||
void audit_log_lost(const char *message)
|
||||
{
|
||||
static unsigned long last_msg = 0;
|
||||
@@ -218,7 +225,6 @@ void audit_log_lost(const char *message)
|
||||
audit_backlog_limit);
|
||||
audit_panic(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int audit_set_rate_limit(int limit, uid_t loginuid)
|
||||
@@ -300,8 +306,22 @@ static int kauditd_thread(void *dummy)
|
||||
remove_wait_queue(&kauditd_wait, &wait);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* audit_send_reply - send an audit reply message via netlink
|
||||
* @pid: process id to send reply to
|
||||
* @seq: sequence number
|
||||
* @type: audit message type
|
||||
* @done: done (last) flag
|
||||
* @multi: multi-part message flag
|
||||
* @payload: payload data
|
||||
* @size: payload size
|
||||
*
|
||||
* Allocates an skb, builds the netlink message, and sends it to the pid.
|
||||
* No failure notifications.
|
||||
*/
|
||||
void audit_send_reply(int pid, int seq, int type, int done, int multi,
|
||||
void *payload, int size)
|
||||
{
|
||||
@@ -342,15 +362,19 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
|
||||
switch (msg_type) {
|
||||
case AUDIT_GET:
|
||||
case AUDIT_LIST:
|
||||
case AUDIT_LIST_RULES:
|
||||
case AUDIT_SET:
|
||||
case AUDIT_ADD:
|
||||
case AUDIT_ADD_RULE:
|
||||
case AUDIT_DEL:
|
||||
case AUDIT_DEL_RULE:
|
||||
case AUDIT_SIGNAL_INFO:
|
||||
if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
|
||||
err = -EPERM;
|
||||
break;
|
||||
case AUDIT_USER:
|
||||
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
|
||||
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
|
||||
if (!cap_raised(eff_cap, CAP_AUDIT_WRITE))
|
||||
err = -EPERM;
|
||||
break;
|
||||
@@ -376,7 +400,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* As soon as there's any sign of userspace auditd, start kauditd to talk to it */
|
||||
/* As soon as there's any sign of userspace auditd,
|
||||
* start kauditd to talk to it */
|
||||
if (!kauditd_task)
|
||||
kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
|
||||
if (IS_ERR(kauditd_task)) {
|
||||
@@ -430,6 +455,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
break;
|
||||
case AUDIT_USER:
|
||||
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
|
||||
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
|
||||
if (!audit_enabled && msg_type != AUDIT_USER_AVC)
|
||||
return 0;
|
||||
|
||||
@@ -448,12 +474,23 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
break;
|
||||
case AUDIT_ADD:
|
||||
case AUDIT_DEL:
|
||||
if (nlh->nlmsg_len < sizeof(struct audit_rule))
|
||||
if (nlmsg_len(nlh) < sizeof(struct audit_rule))
|
||||
return -EINVAL;
|
||||
/* fallthrough */
|
||||
case AUDIT_LIST:
|
||||
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
|
||||
uid, seq, data, loginuid);
|
||||
uid, seq, data, nlmsg_len(nlh),
|
||||
loginuid);
|
||||
break;
|
||||
case AUDIT_ADD_RULE:
|
||||
case AUDIT_DEL_RULE:
|
||||
if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
|
||||
return -EINVAL;
|
||||
/* fallthrough */
|
||||
case AUDIT_LIST_RULES:
|
||||
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
|
||||
uid, seq, data, nlmsg_len(nlh),
|
||||
loginuid);
|
||||
break;
|
||||
case AUDIT_SIGNAL_INFO:
|
||||
sig_data.uid = audit_sig_uid;
|
||||
@@ -469,9 +506,11 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||
return err < 0 ? err : 0;
|
||||
}
|
||||
|
||||
/* Get message from skb (based on rtnetlink_rcv_skb). Each message is
|
||||
/*
|
||||
* Get message from skb (based on rtnetlink_rcv_skb). Each message is
|
||||
* processed by audit_receive_msg. Malformed skbs with wrong length are
|
||||
* discarded silently. */
|
||||
* discarded silently.
|
||||
*/
|
||||
static void audit_receive_skb(struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
@@ -499,14 +538,14 @@ static void audit_receive(struct sock *sk, int length)
|
||||
struct sk_buff *skb;
|
||||
unsigned int qlen;
|
||||
|
||||
down(&audit_netlink_sem);
|
||||
mutex_lock(&audit_netlink_mutex);
|
||||
|
||||
for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
|
||||
skb = skb_dequeue(&sk->sk_receive_queue);
|
||||
audit_receive_skb(skb);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
up(&audit_netlink_sem);
|
||||
mutex_unlock(&audit_netlink_mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -519,8 +558,9 @@ static int __init audit_init(void)
|
||||
THIS_MODULE);
|
||||
if (!audit_sock)
|
||||
audit_panic("cannot initialize netlink socket");
|
||||
else
|
||||
audit_sock->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
|
||||
|
||||
audit_sock->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
|
||||
skb_queue_head_init(&audit_skb_queue);
|
||||
audit_initialized = 1;
|
||||
audit_enabled = audit_default;
|
||||
@@ -600,7 +640,10 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Compute a serial number for the audit record. Audit records are
|
||||
/**
|
||||
* audit_serial - compute a serial number for the audit record
|
||||
*
|
||||
* Compute a serial number for the audit record. Audit records are
|
||||
* written to user-space as soon as they are generated, so a complete
|
||||
* audit record may be written in several pieces. The timestamp of the
|
||||
* record and this serial number are used by the user-space tools to
|
||||
@@ -612,8 +655,8 @@ err:
|
||||
* audit context (for those records that have a context), and emit them
|
||||
* all at syscall exit. However, this could delay the reporting of
|
||||
* significant errors until syscall exit (or never, if the system
|
||||
* halts). */
|
||||
|
||||
* halts).
|
||||
*/
|
||||
unsigned int audit_serial(void)
|
||||
{
|
||||
static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
|
||||
@@ -649,6 +692,21 @@ static inline void audit_get_stamp(struct audit_context *ctx,
|
||||
* 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)
|
||||
* @gfp_mask: type of allocation
|
||||
* @type: audit message type
|
||||
*
|
||||
* Returns audit_buffer pointer on success or NULL on error.
|
||||
*
|
||||
* 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 task (ctx) 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, then
|
||||
* task context (ctx) should be NULL.
|
||||
*/
|
||||
struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
|
||||
int type)
|
||||
{
|
||||
@@ -661,6 +719,9 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
|
||||
if (!audit_initialized)
|
||||
return NULL;
|
||||
|
||||
if (unlikely(audit_filter_type(type)))
|
||||
return NULL;
|
||||
|
||||
if (gfp_mask & __GFP_WAIT)
|
||||
reserve = 0;
|
||||
else
|
||||
@@ -713,6 +774,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
|
||||
/**
|
||||
* audit_expand - expand skb in the audit buffer
|
||||
* @ab: audit_buffer
|
||||
* @extra: space to add at tail of the skb
|
||||
*
|
||||
* Returns 0 (no space) on failed expansion, or available space if
|
||||
* successful.
|
||||
@@ -729,10 +791,12 @@ static inline int audit_expand(struct audit_buffer *ab, int extra)
|
||||
return skb_tailroom(skb);
|
||||
}
|
||||
|
||||
/* Format an audit message into the audit buffer. If there isn't enough
|
||||
/*
|
||||
* Format an audit message into the audit buffer. If there isn't enough
|
||||
* room in the audit buffer, more room will be allocated and vsnprint
|
||||
* will be called a second time. Currently, we assume that a printk
|
||||
* can't format message larger than 1024 bytes, so we don't either. */
|
||||
* can't format message larger than 1024 bytes, so we don't either.
|
||||
*/
|
||||
static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
@@ -757,7 +821,8 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
|
||||
/* The printk buffer is 1024 bytes long, so if we get
|
||||
* here and AUDIT_BUFSIZ is at least 1024, then we can
|
||||
* log everything that printk could have logged. */
|
||||
avail = audit_expand(ab, max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
|
||||
avail = audit_expand(ab,
|
||||
max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
|
||||
if (!avail)
|
||||
goto out;
|
||||
len = vsnprintf(skb->tail, avail, fmt, args2);
|
||||
@@ -768,8 +833,14 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Format a message into the audit buffer. All the work is done in
|
||||
* audit_log_vformat. */
|
||||
/**
|
||||
* audit_log_format - format a message into the audit buffer.
|
||||
* @ab: audit_buffer
|
||||
* @fmt: format string
|
||||
* @...: optional parameters matching @fmt string
|
||||
*
|
||||
* All the work is done in audit_log_vformat.
|
||||
*/
|
||||
void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -781,9 +852,18 @@ void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* This function will take the passed buf and convert it into a string of
|
||||
* ascii hex digits. The new string is placed onto the skb. */
|
||||
void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
|
||||
/**
|
||||
* audit_log_hex - convert a buffer to hex and append it to the audit skb
|
||||
* @ab: the audit_buffer
|
||||
* @buf: buffer to convert to hex
|
||||
* @len: length of @buf to be converted
|
||||
*
|
||||
* No return value; failure to expand is silently ignored.
|
||||
*
|
||||
* This function will take the passed buf and convert it into a string of
|
||||
* ascii hex digits. The new string is placed onto the skb.
|
||||
*/
|
||||
void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
|
||||
size_t len)
|
||||
{
|
||||
int i, avail, new_len;
|
||||
@@ -812,10 +892,16 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
|
||||
skb_put(skb, len << 1); /* new string is twice the old string */
|
||||
}
|
||||
|
||||
/* This code will escape a string that is passed to it if the string
|
||||
* contains a control character, unprintable character, double quote mark,
|
||||
/**
|
||||
* audit_log_unstrustedstring - log a string that may contain random characters
|
||||
* @ab: audit_buffer
|
||||
* @string: string to be logged
|
||||
*
|
||||
* This code will escape a string that is passed to it if the string
|
||||
* contains a control character, unprintable character, double quote mark,
|
||||
* or a space. Unescaped strings will start and end with a double quote mark.
|
||||
* Strings that are escaped are printed in hex (2 digits per char). */
|
||||
* Strings that are escaped are printed in hex (2 digits per char).
|
||||
*/
|
||||
void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
|
||||
{
|
||||
const unsigned char *p = string;
|
||||
@@ -854,10 +940,15 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
|
||||
kfree(path);
|
||||
}
|
||||
|
||||
/* The netlink_* functions cannot be called inside an irq context, so
|
||||
* the audit buffer is places on a queue and a tasklet is scheduled to
|
||||
/**
|
||||
* audit_log_end - end one audit record
|
||||
* @ab: the audit_buffer
|
||||
*
|
||||
* The netlink_* functions cannot be called inside an irq context, so
|
||||
* the audit buffer is placed on a queue and a tasklet is scheduled to
|
||||
* remove them from the queue outside the irq context. May be called in
|
||||
* any context. */
|
||||
* any context.
|
||||
*/
|
||||
void audit_log_end(struct audit_buffer *ab)
|
||||
{
|
||||
if (!ab)
|
||||
@@ -878,9 +969,18 @@ void audit_log_end(struct audit_buffer *ab)
|
||||
audit_buffer_free(ab);
|
||||
}
|
||||
|
||||
/* Log an audit record. This is a convenience function that calls
|
||||
* audit_log_start, audit_log_vformat, and audit_log_end. It may be
|
||||
* called in any context. */
|
||||
/**
|
||||
* audit_log - Log an audit record
|
||||
* @ctx: audit context
|
||||
* @gfp_mask: type of allocation
|
||||
* @type: audit message type
|
||||
* @fmt: format string to use
|
||||
* @...: variable parameters matching the format string
|
||||
*
|
||||
* This is a convenience function that calls audit_log_start,
|
||||
* audit_log_vformat, and audit_log_end. It may be called
|
||||
* in any context.
|
||||
*/
|
||||
void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
@@ -895,3 +995,8 @@ void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
|
||||
audit_log_end(ab);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(audit_log_start);
|
||||
EXPORT_SYMBOL(audit_log_end);
|
||||
EXPORT_SYMBOL(audit_log_format);
|
||||
EXPORT_SYMBOL(audit_log);
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/* audit -- definition of audit_context structure and supporting types
|
||||
*
|
||||
* Copyright 2003-2004 Red Hat, Inc.
|
||||
* Copyright 2005 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright 2005 IBM Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
/* 0 = no checking
|
||||
1 = put_count checking
|
||||
2 = verbose put_count checking
|
||||
*/
|
||||
#define AUDIT_DEBUG 0
|
||||
|
||||
/* At task start time, the audit_state is set in the audit_context using
|
||||
a per-task filter. At syscall entry, the audit_state is augmented by
|
||||
the syscall filter. */
|
||||
enum audit_state {
|
||||
AUDIT_DISABLED, /* Do not create per-task audit_context.
|
||||
* No syscall-specific audit records can
|
||||
* be generated. */
|
||||
AUDIT_SETUP_CONTEXT, /* Create the per-task audit_context,
|
||||
* but don't necessarily fill it in at
|
||||
* syscall entry time (i.e., filter
|
||||
* instead). */
|
||||
AUDIT_BUILD_CONTEXT, /* Create the per-task audit_context,
|
||||
* and always fill it in at syscall
|
||||
* entry time. This makes a full
|
||||
* syscall record available if some
|
||||
* other part of the kernel decides it
|
||||
* should be recorded. */
|
||||
AUDIT_RECORD_CONTEXT /* Create the per-task audit_context,
|
||||
* always fill it in at syscall entry
|
||||
* time, and always write out the audit
|
||||
* record at syscall exit time. */
|
||||
};
|
||||
|
||||
/* Rule lists */
|
||||
struct audit_field {
|
||||
u32 type;
|
||||
u32 val;
|
||||
u32 op;
|
||||
};
|
||||
|
||||
struct audit_krule {
|
||||
int vers_ops;
|
||||
u32 flags;
|
||||
u32 listnr;
|
||||
u32 action;
|
||||
u32 mask[AUDIT_BITMASK_SIZE];
|
||||
u32 buflen; /* for data alloc on list rules */
|
||||
u32 field_count;
|
||||
struct audit_field *fields;
|
||||
};
|
||||
|
||||
struct audit_entry {
|
||||
struct list_head list;
|
||||
struct rcu_head rcu;
|
||||
struct audit_krule rule;
|
||||
};
|
||||
|
||||
|
||||
extern int audit_pid;
|
||||
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
|
||||
|
||||
extern void audit_send_reply(int pid, int seq, int type,
|
||||
int done, int multi,
|
||||
void *payload, int size);
|
||||
extern void audit_log_lost(const char *message);
|
||||
extern void audit_panic(const char *message);
|
||||
extern struct mutex audit_netlink_mutex;
|
||||
File diff suppressed because it is too large
Load Diff
+433
-399
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,7 @@
|
||||
#include <linux/wireless.h>
|
||||
#include <net/iw_handler.h>
|
||||
#include <asm/current.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
/*
|
||||
* The list of packet types we will receive (as opposed to discard)
|
||||
@@ -2147,6 +2148,12 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
|
||||
printk(KERN_INFO "device %s %s promiscuous mode\n",
|
||||
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
|
||||
"left");
|
||||
audit_log(current->audit_context, GFP_ATOMIC,
|
||||
AUDIT_ANOM_PROMISCUOUS,
|
||||
"dev=%s prom=%d old_prom=%d auid=%u",
|
||||
dev->name, (dev->flags & IFF_PROMISC),
|
||||
(old_flags & IFF_PROMISC),
|
||||
audit_get_loginuid(current->audit_context));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -378,7 +378,7 @@ static int dummy_inode_removexattr (struct dentry *dentry, char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -393,6 +393,11 @@ static int dummy_inode_listsecurity(struct inode *inode, char *buffer, size_t bu
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *dummy_inode_xattr_getsuffix(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dummy_file_permission (struct file *file, int mask)
|
||||
{
|
||||
return 0;
|
||||
@@ -558,6 +563,11 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
|
||||
{
|
||||
return 0;
|
||||
@@ -931,6 +941,7 @@ void security_fixup_ops (struct security_operations *ops)
|
||||
set_to_dummy_if_null(ops, inode_getxattr);
|
||||
set_to_dummy_if_null(ops, inode_listxattr);
|
||||
set_to_dummy_if_null(ops, inode_removexattr);
|
||||
set_to_dummy_if_null(ops, inode_xattr_getsuffix);
|
||||
set_to_dummy_if_null(ops, inode_getsecurity);
|
||||
set_to_dummy_if_null(ops, inode_setsecurity);
|
||||
set_to_dummy_if_null(ops, inode_listsecurity);
|
||||
@@ -965,6 +976,7 @@ void security_fixup_ops (struct security_operations *ops)
|
||||
set_to_dummy_if_null(ops, task_reparent_to_init);
|
||||
set_to_dummy_if_null(ops, task_to_inode);
|
||||
set_to_dummy_if_null(ops, ipc_permission);
|
||||
set_to_dummy_if_null(ops, ipc_getsecurity);
|
||||
set_to_dummy_if_null(ops, msg_msg_alloc_security);
|
||||
set_to_dummy_if_null(ops, msg_msg_free_security);
|
||||
set_to_dummy_if_null(ops, msg_queue_alloc_security);
|
||||
|
||||
+46
-52
@@ -119,6 +119,32 @@ static DEFINE_SPINLOCK(sb_security_lock);
|
||||
|
||||
static kmem_cache_t *sel_inode_cache;
|
||||
|
||||
/* Return security context for a given sid or just the context
|
||||
length if the buffer is null or length is 0 */
|
||||
static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
|
||||
{
|
||||
char *context;
|
||||
unsigned len;
|
||||
int rc;
|
||||
|
||||
rc = security_sid_to_context(sid, &context, &len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!buffer || !size)
|
||||
goto getsecurity_exit;
|
||||
|
||||
if (size < len) {
|
||||
len = -ERANGE;
|
||||
goto getsecurity_exit;
|
||||
}
|
||||
memcpy(buffer, context, len);
|
||||
|
||||
getsecurity_exit:
|
||||
kfree(context);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Allocate and free functions for each kind of security blob. */
|
||||
|
||||
static int task_alloc_security(struct task_struct *task)
|
||||
@@ -2210,6 +2236,11 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static const char *selinux_inode_xattr_getsuffix(void)
|
||||
{
|
||||
return XATTR_SELINUX_SUFFIX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the in-core inode security context value to the user. If the
|
||||
* getxattr() prior to this succeeded, check to see if we need to
|
||||
@@ -2217,47 +2248,14 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
|
||||
*
|
||||
* Permission check is handled by selinux_inode_getxattr hook.
|
||||
*/
|
||||
static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
|
||||
{
|
||||
struct inode_security_struct *isec = inode->i_security;
|
||||
char *context;
|
||||
unsigned len;
|
||||
int rc;
|
||||
|
||||
if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
if (strcmp(name, XATTR_SELINUX_SUFFIX))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rc = security_sid_to_context(isec->sid, &context, &len);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* Probe for required buffer size */
|
||||
if (!buffer || !size) {
|
||||
rc = len;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (size < len) {
|
||||
rc = -ERANGE;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (err > 0) {
|
||||
if ((len == err) && !(memcmp(context, buffer, len))) {
|
||||
/* Don't need to canonicalize value */
|
||||
rc = err;
|
||||
goto out_free;
|
||||
}
|
||||
memset(buffer, 0, size);
|
||||
}
|
||||
memcpy(buffer, context, len);
|
||||
rc = len;
|
||||
out_free:
|
||||
kfree(context);
|
||||
out:
|
||||
return rc;
|
||||
return selinux_getsecurity(isec->sid, buffer, size);
|
||||
}
|
||||
|
||||
static int selinux_inode_setsecurity(struct inode *inode, const char *name,
|
||||
@@ -4054,6 +4052,13 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
|
||||
return ipc_has_perm(ipcp, av);
|
||||
}
|
||||
|
||||
static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
|
||||
{
|
||||
struct ipc_security_struct *isec = ipcp->security;
|
||||
|
||||
return selinux_getsecurity(isec->sid, buffer, size);
|
||||
}
|
||||
|
||||
/* module stacking operations */
|
||||
static int selinux_register_security (const char *name, struct security_operations *ops)
|
||||
{
|
||||
@@ -4095,8 +4100,7 @@ static int selinux_getprocattr(struct task_struct *p,
|
||||
char *name, void *value, size_t size)
|
||||
{
|
||||
struct task_security_struct *tsec;
|
||||
u32 sid, len;
|
||||
char *context;
|
||||
u32 sid;
|
||||
int error;
|
||||
|
||||
if (current != p) {
|
||||
@@ -4105,9 +4109,6 @@ static int selinux_getprocattr(struct task_struct *p,
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!size)
|
||||
return -ERANGE;
|
||||
|
||||
tsec = p->security;
|
||||
|
||||
if (!strcmp(name, "current"))
|
||||
@@ -4124,16 +4125,7 @@ static int selinux_getprocattr(struct task_struct *p,
|
||||
if (!sid)
|
||||
return 0;
|
||||
|
||||
error = security_sid_to_context(sid, &context, &len);
|
||||
if (error)
|
||||
return error;
|
||||
if (len > size) {
|
||||
kfree(context);
|
||||
return -ERANGE;
|
||||
}
|
||||
memcpy(value, context, len);
|
||||
kfree(context);
|
||||
return len;
|
||||
return selinux_getsecurity(sid, value, size);
|
||||
}
|
||||
|
||||
static int selinux_setprocattr(struct task_struct *p,
|
||||
@@ -4291,6 +4283,7 @@ static struct security_operations selinux_ops = {
|
||||
.inode_getxattr = selinux_inode_getxattr,
|
||||
.inode_listxattr = selinux_inode_listxattr,
|
||||
.inode_removexattr = selinux_inode_removexattr,
|
||||
.inode_xattr_getsuffix = selinux_inode_xattr_getsuffix,
|
||||
.inode_getsecurity = selinux_inode_getsecurity,
|
||||
.inode_setsecurity = selinux_inode_setsecurity,
|
||||
.inode_listsecurity = selinux_inode_listsecurity,
|
||||
@@ -4328,6 +4321,7 @@ static struct security_operations selinux_ops = {
|
||||
.task_to_inode = selinux_task_to_inode,
|
||||
|
||||
.ipc_permission = selinux_ipc_permission,
|
||||
.ipc_getsecurity = selinux_ipc_getsecurity,
|
||||
|
||||
.msg_msg_alloc_security = selinux_msg_msg_alloc_security,
|
||||
.msg_msg_free_security = selinux_msg_msg_free_security,
|
||||
|
||||
@@ -106,6 +106,9 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
|
||||
{ AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
|
||||
{ AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
|
||||
{ AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
|
||||
{ AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
|
||||
{ AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
|
||||
{ AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
|
||||
{ AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
|
||||
{ AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
|
||||
};
|
||||
@@ -152,8 +155,10 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
|
||||
break;
|
||||
|
||||
case SECCLASS_NETLINK_AUDIT_SOCKET:
|
||||
if (nlmsg_type >= AUDIT_FIRST_USER_MSG &&
|
||||
nlmsg_type <= AUDIT_LAST_USER_MSG) {
|
||||
if ((nlmsg_type >= AUDIT_FIRST_USER_MSG &&
|
||||
nlmsg_type <= AUDIT_LAST_USER_MSG) ||
|
||||
(nlmsg_type >= AUDIT_FIRST_USER_MSG2 &&
|
||||
nlmsg_type <= AUDIT_LAST_USER_MSG2)) {
|
||||
*perm = NETLINK_AUDIT_SOCKET__NLMSG_RELAY;
|
||||
} else {
|
||||
err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user