Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 239

kernel-2.6.18-238.el5.src.rpm

From: Alexander Viro <aviro@redhat.com>
Date: Mon, 8 Dec 2008 14:13:39 -0500
Subject: [audit] records for descr created by pipe and socketpair
Message-id: 20081208191339.GB4523@shell.devel.redhat.com
O-Subject: [rhel5.4][bz#475278] missing audit records for descriptors created by pipe() and socketpair()
Bugzilla: 475278
RH-Acked-by: James Morris <jmorris@redhat.com>
RH-Acked-by: Jiri Pirko <jpirko@redhat.com>
RH-Acked-by: Alan Cox <alan@redhat.com>
RH-Acked-by: James Morris <jmorris@redhat.com>
RH-Acked-by: Jiri Pirko <jpirko@redhat.com>
RH-Acked-by: Alan Cox <alan@redhat.com>
RH-Acked-by: Eric Paris <eparis@redhat.com>

[on top of rhel5 git] [that had been in mainline for almost two years and
I've just found that it hadn't been applied in rhel; oops...]

Provide an audit record of the descriptor pair returned by pipe() and
socketpair().  Rewritten from the original posted to linux-audit by
John D. Ramsdell <ramsdell@mitre.org>

Unlike open() et.al. where we can pick the new fd from return value
(which is recorded), pipe() and socketpair() need the created descriptors
explicitly put into audit record.

backport of mainline commit db3495099d3d52854b13874905af6e40a91f4721
with fixes from commit bf3c23d171e35e6e168074a1514b0acd59cfd81a

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

diff --git a/fs/pipe.c b/fs/pipe.c
index c354412..974591c 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -16,6 +16,7 @@
 #include <linux/uio.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -988,6 +989,10 @@ int do_pipe(int *fd)
 		goto err_fdr;
 	fdw = error;
 
+	error = audit_fd_pair(fdr, fdw);
+	if (error < 0)
+		goto err_fdw;
+
 	fd_install(fdr, fr);
 	fd_install(fdw, fw);
 	fd[0] = fdr;
@@ -995,6 +1000,8 @@ int do_pipe(int *fd)
 
 	return 0;
 
+ err_fdw:
+	put_unused_fd(fdw);
  err_fdr:
 	put_unused_fd(fdr);
  err_read_pipe:
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0d1275b..8285134 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -95,6 +95,7 @@
 #define AUDIT_MQ_NOTIFY		1314	/* POSIX MQ notify record type */
 #define AUDIT_MQ_GETSETATTR	1315	/* POSIX MQ get/set attribute record type */
 #define AUDIT_KERNEL_OTHER	1316	/* For use by 3rd party modules */
+#define AUDIT_FD_PAIR		1317    /* audit record for pipe/socketpair */
 #define AUDIT_OBJ_PID		1318	/* signal target */
 #define AUDIT_TTY		1319	/* Input on an administrative TTY */
 #define AUDIT_EOE		1320	/* End of multi-record event */
@@ -417,6 +418,7 @@ extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, 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_fd_pair(int fd1, int fd2);
 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);
@@ -430,6 +432,12 @@ static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp)
 		return __audit_ipc_obj(ipcp);
 	return 0;
 }
+static inline int audit_fd_pair(int fd1, int fd2)
+{
+	if (unlikely(!audit_dummy_context()))
+		return __audit_fd_pair(fd1, fd2);
+	return 0;
+}
 static inline int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
 {
 	if (unlikely(!audit_dummy_context()))
@@ -490,6 +498,7 @@ extern int audit_signals;
 #define audit_ipc_set_perm(q,u,g,m) ({ 0; })
 #define audit_bprm(p) ({ 0; })
 #define audit_socketcall(n,a) ({ 0; })
+#define audit_fd_pair(n,a) ({ 0; })
 #define audit_sockaddr(len, addr) ({ 0; })
 #define audit_set_macxattr(n) do { ; } while (0)
 #define audit_mq_open(o,m,a) ({ 0; })
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6524dcb..8e8539a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -172,6 +172,11 @@ struct audit_aux_data_sockaddr {
 	char			a[0];
 };
 
+struct audit_aux_data_fd_pair {
+	struct	audit_aux_data d;
+	int	fd[2];
+};
+
 struct audit_aux_data_pids {
 	struct audit_aux_data	d;
 	pid_t			target_pid[AUDIT_AUX_PIDS];
@@ -1332,6 +1337,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 			audit_log_hex(ab, axs->a, axs->len);
 			break; }
 
+		case AUDIT_FD_PAIR: {
+			struct audit_aux_data_fd_pair *axs = (void *)aux;
+			audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
+			break; }
+
 		}
 		audit_log_end(ab);
 	}
@@ -2333,6 +2343,36 @@ int audit_socketcall(int nargs, unsigned long *args)
 }
 
 /**
+ * __audit_fd_pair - record audit data for pipe and socketpair
+ * @fd1: the first file descriptor
+ * @fd2: the second file descriptor
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int __audit_fd_pair(int fd1, int fd2)
+{
+	struct audit_context *context = current->audit_context;
+	struct audit_aux_data_fd_pair *ax;
+
+	if (likely(!context)) {
+		return 0;
+	}
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax) {
+		return -ENOMEM;
+	}
+
+	ax->fd[0] = fd1;
+	ax->fd[1] = fd2;
+
+	ax->d.type = AUDIT_FD_PAIR;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
  * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto
  * @len: data length in user space
  * @a: data address in kernel space
diff --git a/net/socket.c b/net/socket.c
index f63436e..679828a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1286,6 +1286,7 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *u
 {
 	struct socket *sock1, *sock2;
 	int fd1, fd2, err;
+	struct file *newfile1, *newfile2;
 
 	/*
 	 * Obtain the first socket and check if the underlying protocol
@@ -1304,18 +1305,40 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *u
 	if (err < 0) 
 		goto out_release_both;
 
-	fd1 = fd2 = -1;
+	fd1 = sock_alloc_fd(&newfile1);
+	if (unlikely(fd1 < 0)) {
+		err = fd1;
+		goto out_release_both;
+	}
 
-	err = sock_map_fd(sock1);
-	if (err < 0)
+	fd2 = sock_alloc_fd(&newfile2);
+	if (unlikely(fd2 < 0)) {
+		err = fd2;
+		put_filp(newfile1);
+		put_unused_fd(fd1);
 		goto out_release_both;
-	fd1 = err;
+	}
 
-	err = sock_map_fd(sock2);
-	if (err < 0)
-		goto out_close_1;
-	fd2 = err;
+	err = sock_attach_fd(sock1, newfile1);
+	if (unlikely(err < 0)) {
+		goto out_fd2;
+	}
+
+	err = sock_attach_fd(sock2, newfile2);
+	if (unlikely(err < 0)) {
+		fput(newfile1);
+		goto out_fd1;
+	}
 
+	err = audit_fd_pair(fd1, fd2);
+	if (err < 0) {
+		fput(newfile1);
+		fput(newfile2);
+		goto out_fd;
+	}
+
+	fd_install(fd1, newfile1);
+	fd_install(fd2, newfile2);
 	/* fd1 and fd2 may be already another descriptors.
 	 * Not kernel problem.
 	 */
@@ -1330,17 +1353,23 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *u
 	sys_close(fd1);
 	return err;
 
-out_close_1:
-        sock_release(sock2);
-	sys_close(fd1);
-	return err;
-
 out_release_both:
         sock_release(sock2);
 out_release_1:
         sock_release(sock1);
 out:
 	return err;
+
+out_fd2:
+	put_filp(newfile1);
+	sock_release(sock1);
+out_fd1:
+	put_filp(newfile2);
+	sock_release(sock2);
+out_fd:
+	put_unused_fd(fd1);
+	put_unused_fd(fd2);
+	goto out;
 }