Merge branch 'audit.b21' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current

* 'audit.b21' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current: (25 commits)
  [PATCH] make set_loginuid obey audit_enabled
  [PATCH] log more info for directory entry change events
  [PATCH] fix AUDIT_FILTER_PREPEND handling
  [PATCH] validate rule fields' types
  [PATCH] audit: path-based rules
  [PATCH] Audit of POSIX Message Queue Syscalls v.2
  [PATCH] fix se_sen audit filter
  [PATCH] deprecate AUDIT_POSSBILE
  [PATCH] inline more audit helpers
  [PATCH] proc_loginuid_write() uses simple_strtoul() on non-terminated array
  [PATCH] update of IPC audit record cleanup
  [PATCH] minor audit updates
  [PATCH] fix audit_krule_to_{rule,data} return values
  [PATCH] add filtering by ppid
  [PATCH] log ppid
  [PATCH] collect sid of those who send signals to auditd
  [PATCH] execve argument logging
  [PATCH] fix deadlocks in AUDIT_LIST/AUDIT_LIST_RULES
  [PATCH] audit_panic() is audit-internal
  [PATCH] inotify (5/5): update kernel documentation
  ...

Manual fixup of conflict in unclude/linux/inotify.h
This commit is contained in:
Linus Torvalds
2006-06-20 15:37:56 -07:00
27 changed files with 2984 additions and 1056 deletions
+124 -6
View File
@@ -69,17 +69,135 @@ Prototypes:
int inotify_rm_watch (int fd, __u32 mask);
(iii) Internal Kernel Implementation
(iii) Kernel Interface
Each inotify instance is associated with an inotify_device structure.
Inotify's kernel API consists a set of functions for managing watches and an
event callback.
To use the kernel API, you must first initialize an inotify instance with a set
of inotify_operations. You are given an opaque inotify_handle, which you use
for any further calls to inotify.
struct inotify_handle *ih = inotify_init(my_event_handler);
You must provide a function for processing events and a function for destroying
the inotify watch.
void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
u32 cookie, const char *name, struct inode *inode)
watch - the pointer to the inotify_watch that triggered this call
wd - the watch descriptor
mask - describes the event that occurred
cookie - an identifier for synchronizing events
name - the dentry name for affected files in a directory-based event
inode - the affected inode in a directory-based event
void destroy_watch(struct inotify_watch *watch)
You may add watches by providing a pre-allocated and initialized inotify_watch
structure and specifying the inode to watch along with an inotify event mask.
You must pin the inode during the call. You will likely wish to embed the
inotify_watch structure in a structure of your own which contains other
information about the watch. Once you add an inotify watch, it is immediately
subject to removal depending on filesystem events. You must grab a reference if
you depend on the watch hanging around after the call.
inotify_init_watch(&my_watch->iwatch);
inotify_get_watch(&my_watch->iwatch); // optional
s32 wd = inotify_add_watch(ih, &my_watch->iwatch, inode, mask);
inotify_put_watch(&my_watch->iwatch); // optional
You may use the watch descriptor (wd) or the address of the inotify_watch for
other inotify operations. You must not directly read or manipulate data in the
inotify_watch. Additionally, you must not call inotify_add_watch() more than
once for a given inotify_watch structure, unless you have first called either
inotify_rm_watch() or inotify_rm_wd().
To determine if you have already registered a watch for a given inode, you may
call inotify_find_watch(), which gives you both the wd and the watch pointer for
the inotify_watch, or an error if the watch does not exist.
wd = inotify_find_watch(ih, inode, &watchp);
You may use container_of() on the watch pointer to access your own data
associated with a given watch. When an existing watch is found,
inotify_find_watch() bumps the refcount before releasing its locks. You must
put that reference with:
put_inotify_watch(watchp);
Call inotify_find_update_watch() to update the event mask for an existing watch.
inotify_find_update_watch() returns the wd of the updated watch, or an error if
the watch does not exist.
wd = inotify_find_update_watch(ih, inode, mask);
An existing watch may be removed by calling either inotify_rm_watch() or
inotify_rm_wd().
int ret = inotify_rm_watch(ih, &my_watch->iwatch);
int ret = inotify_rm_wd(ih, wd);
A watch may be removed while executing your event handler with the following:
inotify_remove_watch_locked(ih, iwatch);
Call inotify_destroy() to remove all watches from your inotify instance and
release it. If there are no outstanding references, inotify_destroy() will call
your destroy_watch op for each watch.
inotify_destroy(ih);
When inotify removes a watch, it sends an IN_IGNORED event to your callback.
You may use this event as an indication to free the watch memory. Note that
inotify may remove a watch due to filesystem events, as well as by your request.
If you use IN_ONESHOT, inotify will remove the watch after the first event, at
which point you may call the final inotify_put_watch.
(iv) Kernel Interface Prototypes
struct inotify_handle *inotify_init(struct inotify_operations *ops);
inotify_init_watch(struct inotify_watch *watch);
s32 inotify_add_watch(struct inotify_handle *ih,
struct inotify_watch *watch,
struct inode *inode, u32 mask);
s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode,
struct inotify_watch **watchp);
s32 inotify_find_update_watch(struct inotify_handle *ih,
struct inode *inode, u32 mask);
int inotify_rm_wd(struct inotify_handle *ih, u32 wd);
int inotify_rm_watch(struct inotify_handle *ih,
struct inotify_watch *watch);
void inotify_remove_watch_locked(struct inotify_handle *ih,
struct inotify_watch *watch);
void inotify_destroy(struct inotify_handle *ih);
void get_inotify_watch(struct inotify_watch *watch);
void put_inotify_watch(struct inotify_watch *watch);
(v) Internal Kernel Implementation
Each inotify instance is represented by an inotify_handle structure.
Inotify's userspace consumers also have an inotify_device which is
associated with the inotify_handle, and on which events are queued.
Each watch is associated with an inotify_watch structure. Watches are chained
off of each associated device and each associated inode.
off of each associated inotify_handle and each associated inode.
See fs/inotify.c for the locking and lifetime rules.
See fs/inotify.c and fs/inotify_user.c for the locking and lifetime rules.
(iv) Rationale
(vi) Rationale
Q: What is the design decision behind not tying the watch to the open fd of
the watched object?
@@ -145,7 +263,7 @@ A: The poor user-space interface is the second biggest problem with dnotify.
file descriptor-based one that allows basic file I/O and poll/select.
Obtaining the fd and managing the watches could have been done either via a
device file or a family of new system calls. We decided to implement a
family of system calls because that is the preffered approach for new kernel
family of system calls because that is the preferred approach for new kernel
interfaces. The only real difference was whether we wanted to use open(2)
and ioctl(2) or a couple of new system calls. System calls beat ioctls.
+18 -6
View File
@@ -393,18 +393,30 @@ config INOTIFY
bool "Inotify file change notification support"
default y
---help---
Say Y here to enable inotify support and the associated system
calls. Inotify is a file change notification system and a
replacement for dnotify. Inotify fixes numerous shortcomings in
dnotify and introduces several new features. It allows monitoring
of both files and directories via a single open fd. Other features
include multiple file events, one-shot support, and unmount
Say Y here to enable inotify support. Inotify is a file change
notification system and a replacement for dnotify. Inotify fixes
numerous shortcomings in dnotify and introduces several new features
including multiple file events, one-shot support, and unmount
notification.
For more information, see Documentation/filesystems/inotify.txt
If unsure, say Y.
config INOTIFY_USER
bool "Inotify support for userspace"
depends on INOTIFY
default y
---help---
Say Y here to enable inotify support for userspace, including the
associated system calls. Inotify allows monitoring of both files and
directories via a single open fd. Events are read from the file
descriptor, which is also select()- and poll()-able.
For more information, see Documentation/filesystems/inotify.txt
If unsure, say Y.
config QUOTA
bool "Quota support"
help
+1
View File
@@ -13,6 +13,7 @@ obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \
ioprio.o pnode.o drop_caches.o splice.o sync.o
obj-$(CONFIG_INOTIFY) += inotify.o
obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
obj-$(CONFIG_EPOLL) += eventpoll.o
obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
+6
View File
@@ -49,6 +49,7 @@
#include <linux/rmap.h>
#include <linux/acct.h>
#include <linux/cn_proc.h>
#include <linux/audit.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -1085,6 +1086,11 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
/* kernel module loader fixup */
/* so we don't try to load run modprobe in kernel space. */
set_fs(USER_DS);
retval = audit_bprm(bprm);
if (retval)
return retval;
retval = -ENOENT;
for (try=0; try<2; try++) {
read_lock(&binfmt_lock);
+309 -730
View File
File diff suppressed because it is too large Load Diff
+719
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1127,7 +1127,7 @@ out:
if (likely(retval == 0)) {
if (unlikely(current->audit_context && nd && nd->dentry &&
nd->dentry->d_inode))
audit_inode(name, nd->dentry->d_inode, flags);
audit_inode(name, nd->dentry->d_inode);
}
out_fail:
return retval;
+2 -2
View File
@@ -633,7 +633,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
dentry = file->f_dentry;
inode = dentry->d_inode;
audit_inode(NULL, inode, 0);
audit_inode(NULL, inode);
err = -EROFS;
if (IS_RDONLY(inode))
@@ -786,7 +786,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
if (file) {
struct dentry * dentry;
dentry = file->f_dentry;
audit_inode(NULL, dentry->d_inode, 0);
audit_inode(NULL, dentry->d_inode);
error = chown_common(dentry, user, group);
fput(file);
}
+3 -2
View File
@@ -1019,8 +1019,8 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
if (current != task)
return -EPERM;
if (count > PAGE_SIZE)
count = PAGE_SIZE;
if (count >= PAGE_SIZE)
count = PAGE_SIZE - 1;
if (*ppos != 0) {
/* No partial writes. */
@@ -1033,6 +1033,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
if (copy_from_user(page, buf, count))
goto out_free_page;
page[count] = '\0';
loginuid = simple_strtoul(page, &tmp, 10);
if (tmp == page) {
length = -EINVAL;
+2 -2
View File
@@ -242,7 +242,7 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
if (!f)
return error;
dentry = f->f_dentry;
audit_inode(NULL, dentry->d_inode, 0);
audit_inode(NULL, dentry->d_inode);
error = setxattr(dentry, name, value, size, flags);
fput(f);
return error;
@@ -469,7 +469,7 @@ sys_fremovexattr(int fd, char __user *name)
if (!f)
return error;
dentry = f->f_dentry;
audit_inode(NULL, dentry->d_inode, 0);
audit_inode(NULL, dentry->d_inode);
error = removexattr(dentry, name);
fput(f);
return error;
+85 -14
View File
@@ -82,7 +82,12 @@
#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
#define AUDIT_CWD 1307 /* Current working directory */
#define AUDIT_EXECVE 1309 /* execve arguments */
#define AUDIT_IPC_SET_PERM 1311 /* IPC new permissions record type */
#define AUDIT_MQ_OPEN 1312 /* POSIX MQ open record type */
#define AUDIT_MQ_SENDRECV 1313 /* POSIX MQ send/receive record type */
#define AUDIT_MQ_NOTIFY 1314 /* POSIX MQ notify record type */
#define AUDIT_MQ_GETSETATTR 1315 /* POSIX MQ get/set attribute record type */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -150,6 +155,7 @@
#define AUDIT_SE_TYPE 15 /* security label type */
#define AUDIT_SE_SEN 16 /* security label sensitivity label */
#define AUDIT_SE_CLR 17 /* security label clearance label */
#define AUDIT_PPID 18
/* These are ONLY useful when checking
* at syscall exit time (AUDIT_AT_EXIT). */
@@ -158,6 +164,7 @@
#define AUDIT_INODE 102
#define AUDIT_EXIT 103
#define AUDIT_SUCCESS 104 /* exit >= 0; value ignored */
#define AUDIT_WATCH 105
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
@@ -277,12 +284,16 @@ struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
struct audit_sig_info {
uid_t uid;
pid_t pid;
char ctx[0];
};
struct audit_buffer;
struct audit_context;
struct inode;
struct netlink_skb_parms;
struct linux_binprm;
struct mq_attr;
struct mqstat;
#define AUDITSC_INVALID 0
#define AUDITSC_SUCCESS 1
@@ -297,15 +308,19 @@ extern void audit_syscall_entry(int arch,
int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
extern void audit_syscall_exit(int failed, long return_code);
extern void audit_getname(const char *name);
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);
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) {
static inline void audit_getname(const char *name)
{
if (unlikely(current->audit_context))
__audit_inode(name, inode, flags);
__audit_getname(name);
}
static inline void audit_inode(const char *name, const struct inode *inode) {
if (unlikely(current->audit_context))
__audit_inode(name, inode);
}
static inline void audit_inode_child(const char *dname,
const struct inode *inode,
@@ -320,13 +335,61 @@ 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_obj(struct kern_ipc_perm *ipcp);
extern int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
extern int audit_bprm(struct linux_binprm *bprm);
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_set_macxattr(const char *name);
extern int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
if (unlikely(current->audit_context))
return __audit_ipc_obj(ipcp);
return 0;
}
static inline int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
{
if (unlikely(current->audit_context))
return __audit_ipc_set_perm(qbytes, uid, gid, mode);
return 0;
}
static inline int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
{
if (unlikely(current->audit_context))
return __audit_mq_open(oflag, mode, u_attr);
return 0;
}
static inline int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout)
{
if (unlikely(current->audit_context))
return __audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout);
return 0;
}
static inline int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout)
{
if (unlikely(current->audit_context))
return __audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout);
return 0;
}
static inline int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification)
{
if (unlikely(current->audit_context))
return __audit_mq_notify(mqdes, u_notification);
return 0;
}
static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
{
if (unlikely(current->audit_context))
return __audit_mq_getsetattr(mqdes, mqstat);
return 0;
}
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
@@ -334,19 +397,24 @@ extern int audit_set_macxattr(const char *name);
#define audit_syscall_exit(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(n,i) do { ; } while (0)
#define __audit_inode_child(d,i,p) do { ; } while (0)
#define audit_inode(n,i,f) do { ; } while (0)
#define audit_inode(n,i) do { ; } while (0)
#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_obj(i) ({ 0; })
#define audit_ipc_set_perm(q,u,g,m,i) ({ 0; })
#define audit_ipc_set_perm(q,u,g,m) ({ 0; })
#define audit_bprm(p) ({ 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_set_macxattr(n) do { ; } while (0)
#define audit_mq_open(o,m,a) ({ 0; })
#define audit_mq_timedsend(d,l,p,t) ({ 0; })
#define audit_mq_timedreceive(d,l,p,t) ({ 0; })
#define audit_mq_notify(d,n) ({ 0; })
#define audit_mq_getsetattr(d,s) ({ 0; })
#endif
#ifdef CONFIG_AUDIT
@@ -364,8 +432,11 @@ extern void audit_log_end(struct audit_buffer *ab);
extern void audit_log_hex(struct audit_buffer *ab,
const unsigned char *buf,
size_t len);
extern void audit_log_untrustedstring(struct audit_buffer *ab,
extern const char * audit_log_untrustedstring(struct audit_buffer *ab,
const char *string);
extern const char * audit_log_n_untrustedstring(struct audit_buffer *ab,
size_t n,
const char *string);
extern void audit_log_d_path(struct audit_buffer *ab,
const char *prefix,
struct dentry *dentry,
@@ -383,8 +454,8 @@ extern int audit_receive_filter(int type, int pid, int uid, int seq,
#define audit_log_end(b) do { ; } while (0)
#define audit_log_hex(a,b,l) do { ; } while (0)
#define audit_log_untrustedstring(a,s) do { ; } while (0)
#define audit_log_n_untrustedstring(a,n,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
+17 -15
View File
@@ -54,19 +54,20 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
if (isdir)
isdir = IN_ISDIR;
inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name);
inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name);
inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name,
source);
inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name,
source);
if (target) {
inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL);
inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
inotify_inode_is_dead(target);
}
if (source) {
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL);
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
}
audit_inode_child(old_name, source, old_dir->i_ino);
audit_inode_child(new_name, target, new_dir->i_ino);
audit_inode_child(new_name, source, new_dir->i_ino);
}
/*
@@ -85,7 +86,7 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
*/
static inline void fsnotify_inoderemove(struct inode *inode)
{
inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL);
inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
inotify_inode_is_dead(inode);
}
@@ -95,7 +96,8 @@ static inline void fsnotify_inoderemove(struct inode *inode)
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, dentry->d_name.name);
inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
dentry->d_inode);
audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
}
@@ -106,7 +108,7 @@ 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,
dentry->d_name.name);
dentry->d_name.name, dentry->d_inode);
audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
}
@@ -123,7 +125,7 @@ static inline void fsnotify_access(struct dentry *dentry)
dnotify_parent(dentry, DN_ACCESS);
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
inotify_inode_queue_event(inode, mask, 0, NULL);
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -139,7 +141,7 @@ static inline void fsnotify_modify(struct dentry *dentry)
dnotify_parent(dentry, DN_MODIFY);
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
inotify_inode_queue_event(inode, mask, 0, NULL);
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -154,7 +156,7 @@ static inline void fsnotify_open(struct dentry *dentry)
mask |= IN_ISDIR;
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
inotify_inode_queue_event(inode, mask, 0, NULL);
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -172,7 +174,7 @@ static inline void fsnotify_close(struct file *file)
mask |= IN_ISDIR;
inotify_dentry_parent_queue_event(dentry, mask, 0, name);
inotify_inode_queue_event(inode, mask, 0, NULL);
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -187,7 +189,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
mask |= IN_ISDIR;
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
inotify_inode_queue_event(inode, mask, 0, NULL);
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
}
/*
@@ -234,7 +236,7 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
if (in_mask) {
if (S_ISDIR(inode->i_mode))
in_mask |= IN_ISDIR;
inotify_inode_queue_event(inode, in_mask, 0, NULL);
inotify_inode_queue_event(inode, in_mask, 0, NULL, NULL);
inotify_dentry_parent_queue_event(dentry, in_mask, 0,
dentry->d_name.name);
}
+106 -2
View File
@@ -68,18 +68,65 @@ struct inotify_event {
#include <linux/dcache.h>
#include <linux/fs.h>
/*
* struct inotify_watch - represents a watch request on a specific inode
*
* h_list is protected by ih->mutex of the associated inotify_handle.
* i_list, mask are protected by inode->inotify_mutex of the associated inode.
* ih, inode, and wd are never written to once the watch is created.
*
* Callers must use the established inotify interfaces to access inotify_watch
* contents. The content of this structure is private to the inotify
* implementation.
*/
struct inotify_watch {
struct list_head h_list; /* entry in inotify_handle's list */
struct list_head i_list; /* entry in inode's list */
atomic_t count; /* reference count */
struct inotify_handle *ih; /* associated inotify handle */
struct inode *inode; /* associated inode */
__s32 wd; /* watch descriptor */
__u32 mask; /* event mask for this watch */
};
struct inotify_operations {
void (*handle_event)(struct inotify_watch *, u32, u32, u32,
const char *, struct inode *);
void (*destroy_watch)(struct inotify_watch *);
};
#ifdef CONFIG_INOTIFY
/* Kernel API for producing events */
extern void inotify_d_instantiate(struct dentry *, struct inode *);
extern void inotify_d_move(struct dentry *);
extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
const char *);
const char *, struct inode *);
extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
const char *);
extern void inotify_unmount_inodes(struct list_head *);
extern void inotify_inode_is_dead(struct inode *);
extern u32 inotify_get_cookie(void);
/* Kernel Consumer API */
extern struct inotify_handle *inotify_init(const struct inotify_operations *);
extern void inotify_init_watch(struct inotify_watch *);
extern void inotify_destroy(struct inotify_handle *);
extern __s32 inotify_find_watch(struct inotify_handle *, struct inode *,
struct inotify_watch **);
extern __s32 inotify_find_update_watch(struct inotify_handle *, struct inode *,
u32);
extern __s32 inotify_add_watch(struct inotify_handle *, struct inotify_watch *,
struct inode *, __u32);
extern int inotify_rm_watch(struct inotify_handle *, struct inotify_watch *);
extern int inotify_rm_wd(struct inotify_handle *, __u32);
extern void inotify_remove_watch_locked(struct inotify_handle *,
struct inotify_watch *);
extern void get_inotify_watch(struct inotify_watch *);
extern void put_inotify_watch(struct inotify_watch *);
#else
static inline void inotify_d_instantiate(struct dentry *dentry,
@@ -93,7 +140,8 @@ static inline void inotify_d_move(struct dentry *dentry)
static inline void inotify_inode_queue_event(struct inode *inode,
__u32 mask, __u32 cookie,
const char *filename)
const char *filename,
struct inode *n_inode)
{
}
@@ -116,6 +164,62 @@ static inline u32 inotify_get_cookie(void)
return 0;
}
static inline struct inotify_handle *inotify_init(const struct inotify_operations *ops)
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline void inotify_init_watch(struct inotify_watch *watch)
{
}
static inline void inotify_destroy(struct inotify_handle *ih)
{
}
static inline __s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode,
struct inotify_watch **watchp)
{
return -EOPNOTSUPP;
}
static inline __s32 inotify_find_update_watch(struct inotify_handle *ih,
struct inode *inode, u32 mask)
{
return -EOPNOTSUPP;
}
static inline __s32 inotify_add_watch(struct inotify_handle *ih,
struct inotify_watch *watch,
struct inode *inode, __u32 mask)
{
return -EOPNOTSUPP;
}
static inline int inotify_rm_watch(struct inotify_handle *ih,
struct inotify_watch *watch)
{
return -EOPNOTSUPP;
}
static inline int inotify_rm_wd(struct inotify_handle *ih, __u32 wd)
{
return -EOPNOTSUPP;
}
static inline void inotify_remove_watch_locked(struct inotify_handle *ih,
struct inotify_watch *watch)
{
}
static inline void get_inotify_watch(struct inotify_watch *watch)
{
}
static inline void put_inotify_watch(struct inotify_watch *watch)
{
}
#endif /* CONFIG_INOTIFY */
#endif /* __KERNEL __ */
+1 -1
View File
@@ -494,7 +494,7 @@ struct user_struct {
atomic_t processes; /* How many processes does this user have? */
atomic_t files; /* How many open files does this user have? */
atomic_t sigpending; /* How many pending signals does this user have? */
#ifdef CONFIG_INOTIFY
#ifdef CONFIG_INOTIFY_USER
atomic_t inotify_watches; /* How many inotify watches does this user have? */
atomic_t inotify_devs; /* How many inotify devs does this user have opened? */
#endif
+2 -1
View File
@@ -182,7 +182,8 @@ config AUDITSYSCALL
help
Enable low-overhead system-call auditing infrastructure that
can be used independently or with another kernel subsystem,
such as SELinux.
such as SELinux. To use audit's filesystem watch feature, please
ensure that INOTIFY is configured.
config IKCONFIG
bool "Kernel .config support"
+22
View File
@@ -8,6 +8,8 @@
* Lockless receive & send, fd based notify:
* Manfred Spraul (manfred@colorfullife.com)
*
* Audit: George Wilson (ltcgcw@us.ibm.com)
*
* This file is released under the GPL.
*/
@@ -24,6 +26,7 @@
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/syscalls.h>
#include <linux/audit.h>
#include <linux/signal.h>
#include <linux/mutex.h>
@@ -657,6 +660,10 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
char *name;
int fd, error;
error = audit_mq_open(oflag, mode, u_attr);
if (error != 0)
return error;
if (IS_ERR(name = getname(u_name)))
return PTR_ERR(name);
@@ -814,6 +821,10 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
long timeout;
int ret;
ret = audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout);
if (ret != 0)
return ret;
if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
return -EINVAL;
@@ -896,6 +907,10 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
struct mqueue_inode_info *info;
struct ext_wait_queue wait;
ret = audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout);
if (ret != 0)
return ret;
timeout = prepare_timeout(u_abs_timeout);
ret = -EBADF;
@@ -975,6 +990,10 @@ asmlinkage long sys_mq_notify(mqd_t mqdes,
struct mqueue_inode_info *info;
struct sk_buff *nc;
ret = audit_mq_notify(mqdes, u_notification);
if (ret != 0)
return ret;
nc = NULL;
sock = NULL;
if (u_notification != NULL) {
@@ -1115,6 +1134,9 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes,
omqstat = info->attr;
omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
if (u_mqstat) {
ret = audit_mq_getsetattr(mqdes, &mqstat);
if (ret != 0)
goto out;
if (mqstat.mq_flags & O_NONBLOCK)
filp->f_flags |= O_NONBLOCK;
else
+5 -4
View File
@@ -454,6 +454,11 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
err = audit_ipc_obj(ipcp);
if (err)
goto out_unlock_up;
if (cmd==IPC_SET) {
err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode);
if (err)
goto out_unlock_up;
}
err = -EPERM;
if (current->euid != ipcp->cuid &&
@@ -468,10 +473,6 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
switch (cmd) {
case IPC_SET:
{
err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
if (err)
goto out_unlock_up;
err = -EPERM;
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
+5 -3
View File
@@ -828,6 +828,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
if (err)
goto out_unlock;
if (cmd == IPC_SET) {
err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode);
if (err)
goto out_unlock;
}
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
err=-EPERM;
@@ -844,9 +849,6 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
err = 0;
break;
case IPC_SET:
err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
if (err)
goto out_unlock;
ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
+1 -1
View File
@@ -643,7 +643,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
err = audit_ipc_obj(&(shp->shm_perm));
if (err)
goto out_unlock_up;
err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm));
err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode);
if (err)
goto out_unlock_up;
err=-EPERM;
+158 -47
View File
@@ -56,6 +56,7 @@
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/selinux.h>
#include <linux/inotify.h>
#include "audit.h"
@@ -89,6 +90,7 @@ static int audit_backlog_wait_overflow = 0;
/* The identity of the user shutting down the audit system. */
uid_t audit_sig_uid = -1;
pid_t audit_sig_pid = -1;
u32 audit_sig_sid = 0;
/* Records can be lost in several ways:
0) [suppressed in audit_alloc]
@@ -102,6 +104,12 @@ static atomic_t audit_lost = ATOMIC_INIT(0);
/* The netlink socket. */
static struct sock *audit_sock;
/* Inotify handle. */
struct inotify_handle *audit_ih;
/* Hash for inode-based rules */
struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
/* The audit_freelist is a list of pre-allocated audit buffers (if more
* than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
* being placed on the freelist). */
@@ -114,10 +122,8 @@ static struct task_struct *kauditd_task;
static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
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 */
DEFINE_MUTEX(audit_netlink_mutex);
/* Serialize requests from userspace. */
static DEFINE_MUTEX(audit_cmd_mutex);
/* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
* audit records. Since printk uses a 1024 byte buffer, this buffer
@@ -250,7 +256,7 @@ static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
"audit_rate_limit=%d old=%d by auid=%u",
limit, old, loginuid);
audit_rate_limit = limit;
return old;
return 0;
}
static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
@@ -273,7 +279,7 @@ static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
"audit_backlog_limit=%d old=%d by auid=%u",
limit, old, loginuid);
audit_backlog_limit = limit;
return old;
return 0;
}
static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
@@ -299,7 +305,7 @@ static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
"audit_enabled=%d old=%d by auid=%u",
state, old, loginuid);
audit_enabled = state;
return old;
return 0;
}
static int audit_set_failure(int state, uid_t loginuid, u32 sid)
@@ -327,7 +333,7 @@ static int audit_set_failure(int state, uid_t loginuid, u32 sid)
"audit_failure=%d old=%d by auid=%u",
state, old, loginuid);
audit_failure = state;
return old;
return 0;
}
static int kauditd_thread(void *dummy)
@@ -363,9 +369,52 @@ static int kauditd_thread(void *dummy)
remove_wait_queue(&kauditd_wait, &wait);
}
}
}
int audit_send_list(void *_dest)
{
struct audit_netlink_list *dest = _dest;
int pid = dest->pid;
struct sk_buff *skb;
/* wait for parent to finish and send an ACK */
mutex_lock(&audit_cmd_mutex);
mutex_unlock(&audit_cmd_mutex);
while ((skb = __skb_dequeue(&dest->q)) != NULL)
netlink_unicast(audit_sock, skb, pid, 0);
kfree(dest);
return 0;
}
struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
int multi, void *payload, int size)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
int len = NLMSG_SPACE(size);
void *data;
int flags = multi ? NLM_F_MULTI : 0;
int t = done ? NLMSG_DONE : type;
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return NULL;
nlh = NLMSG_PUT(skb, pid, seq, t, size);
nlh->nlmsg_flags = flags;
data = NLMSG_DATA(nlh);
memcpy(data, payload, size);
return skb;
nlmsg_failure: /* Used by NLMSG_PUT */
if (skb)
kfree_skb(skb);
return NULL;
}
/**
* audit_send_reply - send an audit reply message via netlink
* @pid: process id to send reply to
@@ -383,29 +432,13 @@ void audit_send_reply(int pid, int seq, int type, int done, int multi,
void *payload, int size)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
int len = NLMSG_SPACE(size);
void *data;
int flags = multi ? NLM_F_MULTI : 0;
int t = done ? NLMSG_DONE : type;
skb = alloc_skb(len, GFP_KERNEL);
skb = audit_make_reply(pid, seq, type, done, multi, payload, size);
if (!skb)
return;
nlh = NLMSG_PUT(skb, pid, seq, t, size);
nlh->nlmsg_flags = flags;
data = NLMSG_DATA(nlh);
memcpy(data, payload, size);
/* Ignore failure. It'll only happen if the sender goes away,
because our timeout is set to infinite. */
netlink_unicast(audit_sock, skb, pid, 0);
return;
nlmsg_failure: /* Used by NLMSG_PUT */
if (skb)
kfree_skb(skb);
}
/*
@@ -451,7 +484,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
struct audit_buffer *ab;
u16 msg_type = nlh->nlmsg_type;
uid_t loginuid; /* loginuid of sender */
struct audit_sig_info sig_data;
struct audit_sig_info *sig_data;
char *ctx;
u32 len;
err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type);
if (err)
@@ -503,12 +538,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (status_get->mask & AUDIT_STATUS_PID) {
int old = audit_pid;
if (sid) {
char *ctx = NULL;
u32 len;
int rc;
if ((rc = selinux_ctxid_to_string(
if ((err = selinux_ctxid_to_string(
sid, &ctx, &len)))
return rc;
return err;
else
audit_log(NULL, GFP_KERNEL,
AUDIT_CONFIG_CHANGE,
@@ -523,10 +555,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
audit_pid = status_get->pid;
}
if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
audit_set_rate_limit(status_get->rate_limit,
err = audit_set_rate_limit(status_get->rate_limit,
loginuid, sid);
if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
audit_set_backlog_limit(status_get->backlog_limit,
err = audit_set_backlog_limit(status_get->backlog_limit,
loginuid, sid);
break;
case AUDIT_USER:
@@ -544,8 +576,6 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
"user pid=%d uid=%u auid=%u",
pid, uid, loginuid);
if (sid) {
char *ctx = NULL;
u32 len;
if (selinux_ctxid_to_string(
sid, &ctx, &len)) {
audit_log_format(ab,
@@ -584,10 +614,21 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
loginuid, sid);
break;
case AUDIT_SIGNAL_INFO:
sig_data.uid = audit_sig_uid;
sig_data.pid = audit_sig_pid;
err = selinux_ctxid_to_string(audit_sig_sid, &ctx, &len);
if (err)
return err;
sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
if (!sig_data) {
kfree(ctx);
return -ENOMEM;
}
sig_data->uid = audit_sig_uid;
sig_data->pid = audit_sig_pid;
memcpy(sig_data->ctx, ctx, len);
kfree(ctx);
audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO,
0, 0, &sig_data, sizeof(sig_data));
0, 0, sig_data, sizeof(*sig_data) + len);
kfree(sig_data);
break;
default:
err = -EINVAL;
@@ -629,20 +670,30 @@ static void audit_receive(struct sock *sk, int length)
struct sk_buff *skb;
unsigned int qlen;
mutex_lock(&audit_netlink_mutex);
mutex_lock(&audit_cmd_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);
}
mutex_unlock(&audit_netlink_mutex);
mutex_unlock(&audit_cmd_mutex);
}
#ifdef CONFIG_AUDITSYSCALL
static const struct inotify_operations audit_inotify_ops = {
.handle_event = audit_handle_ievent,
.destroy_watch = audit_free_parent,
};
#endif
/* Initialize audit support at boot time. */
static int __init audit_init(void)
{
#ifdef CONFIG_AUDITSYSCALL
int i;
#endif
printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
audit_default ? "enabled" : "disabled");
audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive,
@@ -661,6 +712,16 @@ static int __init audit_init(void)
selinux_audit_set_callback(&selinux_audit_rule_update);
audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
#ifdef CONFIG_AUDITSYSCALL
audit_ih = inotify_init(&audit_inotify_ops);
if (IS_ERR(audit_ih))
audit_panic("cannot initialize inotify handle");
for (i = 0; i < AUDIT_INODE_BUCKETS; i++)
INIT_LIST_HEAD(&audit_inode_hash[i]);
#endif
return 0;
}
__initcall(audit_init);
@@ -690,10 +751,12 @@ static void audit_buffer_free(struct audit_buffer *ab)
kfree_skb(ab->skb);
spin_lock_irqsave(&audit_freelist_lock, flags);
if (++audit_freelist_count > AUDIT_MAXFREE)
if (audit_freelist_count > AUDIT_MAXFREE)
kfree(ab);
else
else {
audit_freelist_count++;
list_add(&ab->list, &audit_freelist);
}
spin_unlock_irqrestore(&audit_freelist_lock, flags);
}
@@ -988,28 +1051,76 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
skb_put(skb, len << 1); /* new string is twice the old string */
}
/*
* Format a string of no more than slen characters into the audit buffer,
* enclosed in quote marks.
*/
static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
const char *string)
{
int avail, new_len;
unsigned char *ptr;
struct sk_buff *skb;
BUG_ON(!ab->skb);
skb = ab->skb;
avail = skb_tailroom(skb);
new_len = slen + 3; /* enclosing quotes + null terminator */
if (new_len > avail) {
avail = audit_expand(ab, new_len);
if (!avail)
return;
}
ptr = skb->tail;
*ptr++ = '"';
memcpy(ptr, string, slen);
ptr += slen;
*ptr++ = '"';
*ptr = 0;
skb_put(skb, slen + 2); /* don't include null terminator */
}
/**
* audit_log_unstrustedstring - log a string that may contain random characters
* audit_log_n_unstrustedstring - log a string that may contain random characters
* @ab: audit_buffer
* @len: lenth of string (not including trailing null)
* @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).
*
* The caller specifies the number of characters in the string to log, which may
* or may not be the entire string.
*/
void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
const char *string)
{
const unsigned char *p = string;
while (*p) {
if (*p == '"' || *p < 0x21 || *p > 0x7f) {
audit_log_hex(ab, string, strlen(string));
return;
audit_log_hex(ab, string, len);
return string + len + 1;
}
p++;
}
audit_log_format(ab, "\"%s\"", string);
audit_log_n_string(ab, len, string);
return p + 1;
}
/**
* audit_log_unstrustedstring - log a string that may contain random characters
* @ab: audit_buffer
* @string: string to be logged
*
* Same as audit_log_n_unstrustedstring(), except that strlen is used to
* determine string length.
*/
const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
{
return audit_log_n_untrustedstring(ab, strlen(string), string);
}
/* This is a helper-function to print the escaped d_path */

Some files were not shown because too many files have changed in this diff Show More