mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-24 17:23:25 -05:00
[PATCH] Rework of IPC auditing
1) The audit_ipc_perms() function has been split into two different functions: - audit_ipc_obj() - audit_ipc_set_perm() There's a key shift here... The audit_ipc_obj() collects the uid, gid, mode, and SElinux context label of the current ipc object. This audit_ipc_obj() hook is now found in several places. Most notably, it is hooked in ipcperms(), which is called in various places around the ipc code permforming a MAC check. Additionally there are several places where *checkid() is used to validate that an operation is being performed on a valid object while not necessarily having a nearby ipcperms() call. In these locations, audit_ipc_obj() is called to ensure that the information is captured by the audit system. The audit_set_new_perm() function is called any time the permissions on the ipc object changes. In this case, the NEW permissions are recorded (and note that an audit_ipc_obj() call exists just a few lines before each instance). 2) Support for an AUDIT_IPC_SET_PERM audit message type. This allows for separate auxiliary audit records for normal operations on an IPC object and permissions changes. Note that the same struct audit_aux_data_ipcctl is used and populated, however there are separate audit_log_format statements based on the type of the message. Finally, the AUDIT_IPC block of code in audit_free_aux() was extended to handle aux messages of this new type. No more mem leaks I hope ;-) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
ce29b682e2
commit
073115d6b2
6 changed files with 98 additions and 11 deletions
|
@ -83,6 +83,7 @@
|
||||||
#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
|
#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
|
||||||
#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
|
#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
|
||||||
#define AUDIT_CWD 1307 /* Current working directory */
|
#define AUDIT_CWD 1307 /* Current working directory */
|
||||||
|
#define AUDIT_IPC_SET_PERM 1311 /* IPC new permissions record type */
|
||||||
|
|
||||||
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
|
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
|
||||||
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
|
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
|
||||||
|
@ -319,7 +320,8 @@ extern void auditsc_get_stamp(struct audit_context *ctx,
|
||||||
struct timespec *t, unsigned int *serial);
|
struct timespec *t, unsigned int *serial);
|
||||||
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
|
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
|
||||||
extern uid_t audit_get_loginuid(struct audit_context *ctx);
|
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, 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, struct kern_ipc_perm *ipcp);
|
||||||
extern int audit_socketcall(int nargs, unsigned long *args);
|
extern int audit_socketcall(int nargs, unsigned long *args);
|
||||||
extern int audit_sockaddr(int len, void *addr);
|
extern int audit_sockaddr(int len, void *addr);
|
||||||
extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
|
extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
|
||||||
|
@ -338,7 +340,8 @@ extern int audit_set_macxattr(const char *name);
|
||||||
#define audit_inode_child(d,i,p) 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 auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
|
||||||
#define audit_get_loginuid(c) ({ -1; })
|
#define audit_get_loginuid(c) ({ -1; })
|
||||||
#define audit_ipc_perms(q,u,g,m,i) ({ 0; })
|
#define audit_ipc_obj(i) ({ 0; })
|
||||||
|
#define audit_ipc_set_perm(q,u,g,m,i) ({ 0; })
|
||||||
#define audit_socketcall(n,a) ({ 0; })
|
#define audit_socketcall(n,a) ({ 0; })
|
||||||
#define audit_sockaddr(len, addr) ({ 0; })
|
#define audit_sockaddr(len, addr) ({ 0; })
|
||||||
#define audit_avc_path(dentry, mnt) ({ 0; })
|
#define audit_avc_path(dentry, mnt) ({ 0; })
|
||||||
|
|
11
ipc/msg.c
11
ipc/msg.c
|
@ -13,6 +13,9 @@
|
||||||
* mostly rewritten, threaded and wake-one semantics added
|
* mostly rewritten, threaded and wake-one semantics added
|
||||||
* MSGMAX limit removed, sysctl's added
|
* MSGMAX limit removed, sysctl's added
|
||||||
* (c) 1999 Manfred Spraul <manfred@colorfullife.com>
|
* (c) 1999 Manfred Spraul <manfred@colorfullife.com>
|
||||||
|
*
|
||||||
|
* support for audit of ipc object properties and permission changes
|
||||||
|
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
|
@ -447,6 +450,11 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
|
||||||
if (msg_checkid(msq,msqid))
|
if (msg_checkid(msq,msqid))
|
||||||
goto out_unlock_up;
|
goto out_unlock_up;
|
||||||
ipcp = &msq->q_perm;
|
ipcp = &msq->q_perm;
|
||||||
|
|
||||||
|
err = audit_ipc_obj(ipcp);
|
||||||
|
if (err)
|
||||||
|
goto out_unlock_up;
|
||||||
|
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
if (current->euid != ipcp->cuid &&
|
if (current->euid != ipcp->cuid &&
|
||||||
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
|
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
|
||||||
|
@ -460,7 +468,8 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case IPC_SET:
|
case IPC_SET:
|
||||||
{
|
{
|
||||||
if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
|
err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
|
||||||
|
if (err)
|
||||||
goto out_unlock_up;
|
goto out_unlock_up;
|
||||||
|
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
|
|
11
ipc/sem.c
11
ipc/sem.c
|
@ -61,6 +61,9 @@
|
||||||
* (c) 2001 Red Hat Inc <alan@redhat.com>
|
* (c) 2001 Red Hat Inc <alan@redhat.com>
|
||||||
* Lockless wakeup
|
* Lockless wakeup
|
||||||
* (c) 2003 Manfred Spraul <manfred@colorfullife.com>
|
* (c) 2003 Manfred Spraul <manfred@colorfullife.com>
|
||||||
|
*
|
||||||
|
* support for audit of ipc object properties and permission changes
|
||||||
|
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
|
@ -820,6 +823,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
ipcp = &sma->sem_perm;
|
ipcp = &sma->sem_perm;
|
||||||
|
|
||||||
|
err = audit_ipc_obj(ipcp);
|
||||||
|
if (err)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
if (current->euid != ipcp->cuid &&
|
if (current->euid != ipcp->cuid &&
|
||||||
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
|
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
|
||||||
err=-EPERM;
|
err=-EPERM;
|
||||||
|
@ -836,7 +844,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
case IPC_SET:
|
case IPC_SET:
|
||||||
if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
|
err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
|
||||||
|
if (err)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
ipcp->uid = setbuf.uid;
|
ipcp->uid = setbuf.uid;
|
||||||
ipcp->gid = setbuf.gid;
|
ipcp->gid = setbuf.gid;
|
||||||
|
|
19
ipc/shm.c
19
ipc/shm.c
|
@ -13,6 +13,8 @@
|
||||||
* Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
|
* Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
|
||||||
* Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
|
* Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
|
||||||
*
|
*
|
||||||
|
* support for audit of ipc object properties and permission changes
|
||||||
|
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
|
@ -542,6 +544,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
|
||||||
if(err)
|
if(err)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
err = audit_ipc_obj(&(shp->shm_perm));
|
||||||
|
if (err)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
if (!capable(CAP_IPC_LOCK)) {
|
if (!capable(CAP_IPC_LOCK)) {
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
if (current->euid != shp->shm_perm.uid &&
|
if (current->euid != shp->shm_perm.uid &&
|
||||||
|
@ -594,6 +600,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
|
||||||
if(err)
|
if(err)
|
||||||
goto out_unlock_up;
|
goto out_unlock_up;
|
||||||
|
|
||||||
|
err = audit_ipc_obj(&(shp->shm_perm));
|
||||||
|
if (err)
|
||||||
|
goto out_unlock_up;
|
||||||
|
|
||||||
if (current->euid != shp->shm_perm.uid &&
|
if (current->euid != shp->shm_perm.uid &&
|
||||||
current->euid != shp->shm_perm.cuid &&
|
current->euid != shp->shm_perm.cuid &&
|
||||||
!capable(CAP_SYS_ADMIN)) {
|
!capable(CAP_SYS_ADMIN)) {
|
||||||
|
@ -627,12 +637,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
|
||||||
err=-EINVAL;
|
err=-EINVAL;
|
||||||
if(shp==NULL)
|
if(shp==NULL)
|
||||||
goto out_up;
|
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);
|
err = shm_checkid(shp,shmid);
|
||||||
if(err)
|
if(err)
|
||||||
goto out_unlock_up;
|
goto out_unlock_up;
|
||||||
|
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));
|
||||||
|
if (err)
|
||||||
|
goto out_unlock_up;
|
||||||
err=-EPERM;
|
err=-EPERM;
|
||||||
if (current->euid != shp->shm_perm.uid &&
|
if (current->euid != shp->shm_perm.uid &&
|
||||||
current->euid != shp->shm_perm.cuid &&
|
current->euid != shp->shm_perm.cuid &&
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
* Manfred Spraul <manfred@colorfullife.com>
|
* Manfred Spraul <manfred@colorfullife.com>
|
||||||
* Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().
|
* Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().
|
||||||
* Mingming Cao <cmm@us.ibm.com>
|
* Mingming Cao <cmm@us.ibm.com>
|
||||||
|
* Mar 2006 - support for audit of ipc object properties
|
||||||
|
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
|
@ -27,6 +29,7 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/audit.h>
|
||||||
|
|
||||||
#include <asm/unistd.h>
|
#include <asm/unistd.h>
|
||||||
|
|
||||||
|
@ -464,8 +467,10 @@ void ipc_rcu_putref(void *ptr)
|
||||||
|
|
||||||
int ipcperms (struct kern_ipc_perm *ipcp, short flag)
|
int ipcperms (struct kern_ipc_perm *ipcp, short flag)
|
||||||
{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
|
{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
|
||||||
int requested_mode, granted_mode;
|
int requested_mode, granted_mode, err;
|
||||||
|
|
||||||
|
if (unlikely((err = audit_ipc_obj(ipcp))))
|
||||||
|
return err;
|
||||||
requested_mode = (flag >> 6) | (flag >> 3) | flag;
|
requested_mode = (flag >> 6) | (flag >> 3) | flag;
|
||||||
granted_mode = ipcp->mode;
|
granted_mode = ipcp->mode;
|
||||||
if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
|
if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
|
||||||
|
|
|
@ -646,6 +646,25 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
|
||||||
}
|
}
|
||||||
break; }
|
break; }
|
||||||
|
|
||||||
|
case AUDIT_IPC_SET_PERM: {
|
||||||
|
struct audit_aux_data_ipcctl *axi = (void *)aux;
|
||||||
|
audit_log_format(ab,
|
||||||
|
" new qbytes=%lx new iuid=%u new igid=%u new mode=%x",
|
||||||
|
axi->qbytes, axi->uid, axi->gid, axi->mode);
|
||||||
|
if (axi->osid != 0) {
|
||||||
|
char *ctx = NULL;
|
||||||
|
u32 len;
|
||||||
|
if (selinux_ctxid_to_string(
|
||||||
|
axi->osid, &ctx, &len)) {
|
||||||
|
audit_log_format(ab, " osid=%u",
|
||||||
|
axi->osid);
|
||||||
|
call_panic = 1;
|
||||||
|
} else
|
||||||
|
audit_log_format(ab, " obj=%s", ctx);
|
||||||
|
kfree(ctx);
|
||||||
|
}
|
||||||
|
break; }
|
||||||
|
|
||||||
case AUDIT_SOCKETCALL: {
|
case AUDIT_SOCKETCALL: {
|
||||||
int i;
|
int i;
|
||||||
struct audit_aux_data_socketcall *axs = (void *)aux;
|
struct audit_aux_data_socketcall *axs = (void *)aux;
|
||||||
|
@ -1148,7 +1167,36 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* audit_ipc_perms - record audit data for ipc
|
* audit_ipc_obj - record audit data for ipc object
|
||||||
|
* @ipcp: ipc permissions
|
||||||
|
*
|
||||||
|
* Returns 0 for success or NULL context or < 0 on error.
|
||||||
|
*/
|
||||||
|
int audit_ipc_obj(struct kern_ipc_perm *ipcp)
|
||||||
|
{
|
||||||
|
struct audit_aux_data_ipcctl *ax;
|
||||||
|
struct audit_context *context = current->audit_context;
|
||||||
|
|
||||||
|
if (likely(!context))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
|
||||||
|
if (!ax)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ax->uid = ipcp->uid;
|
||||||
|
ax->gid = ipcp->gid;
|
||||||
|
ax->mode = ipcp->mode;
|
||||||
|
selinux_get_ipc_sid(ipcp, &ax->osid);
|
||||||
|
|
||||||
|
ax->d.type = AUDIT_IPC;
|
||||||
|
ax->d.next = context->aux;
|
||||||
|
context->aux = (void *)ax;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audit_ipc_set_perm - record audit data for new ipc permissions
|
||||||
* @qbytes: msgq bytes
|
* @qbytes: msgq bytes
|
||||||
* @uid: msgq user id
|
* @uid: msgq user id
|
||||||
* @gid: msgq group id
|
* @gid: msgq group id
|
||||||
|
@ -1156,7 +1204,7 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
|
||||||
*
|
*
|
||||||
* Returns 0 for success or NULL context or < 0 on error.
|
* Returns 0 for success or NULL context or < 0 on error.
|
||||||
*/
|
*/
|
||||||
int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
|
int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
|
||||||
{
|
{
|
||||||
struct audit_aux_data_ipcctl *ax;
|
struct audit_aux_data_ipcctl *ax;
|
||||||
struct audit_context *context = current->audit_context;
|
struct audit_context *context = current->audit_context;
|
||||||
|
@ -1174,7 +1222,7 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, str
|
||||||
ax->mode = mode;
|
ax->mode = mode;
|
||||||
selinux_get_ipc_sid(ipcp, &ax->osid);
|
selinux_get_ipc_sid(ipcp, &ax->osid);
|
||||||
|
|
||||||
ax->d.type = AUDIT_IPC;
|
ax->d.type = AUDIT_IPC_SET_PERM;
|
||||||
ax->d.next = context->aux;
|
ax->d.next = context->aux;
|
||||||
context->aux = (void *)ax;
|
context->aux = (void *)ax;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue