[PATCH 06/11] capsicum: implement sockfd_lookupr()

From: David Drysdale
Date: Mon Jun 30 2014 - 06:34:59 EST


Add variants of sockfd_lookup() and related functions where the caller
indicates the operations that will be performed on the socket.

If CONFIG_SECURITY_CAPSICUM is defined, these variants use the
fgetr()-style functions to retrieve the struct file from the file
descriptor.

If CONFIG_SECURITY_CAPSICUM is not defined, these variants use the
normal fget() functions.

Signed-off-by: David Drysdale <drysdale@xxxxxxxxxx>
---
include/linux/net.h | 16 +++++++
net/socket.c | 118 ++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 117 insertions(+), 17 deletions(-)

diff --git a/include/linux/net.h b/include/linux/net.h
index 17d83393afcc..05429ce3b730 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -24,6 +24,7 @@
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
#include <linux/kmemcheck.h>
#include <linux/rcupdate.h>
+#include <linux/capsicum.h>
#include <linux/jump_label.h>
#include <uapi/linux/net.h>

@@ -222,6 +223,21 @@ struct socket *sock_from_file(struct file *file, int *err);
#define sockfd_put(sock) fput(sock->file)
int net_ratelimit(void);

+#ifdef CONFIG_SECURITY_CAPSICUM
+struct socket *sockfd_lookup_rights(int fd, int *err,
+ struct capsicum_rights *rights);
+struct socket *_sockfd_lookupr(int fd, int *err, ...);
+#define sockfd_lookupr(fd, err, ...) \
+ _sockfd_lookupr((fd), (err), __VA_ARGS__, 0ULL)
+#else
+static inline struct socket *
+sockfd_lookup_rights(int fd, int *err, struct capsicum_rights *rights)
+{
+ return sockfd_lookup(fd, err);
+}
+#define sockfd_lookupr(fd, err, ...) sockfd_lookup((fd), (err))
+#endif
+
#define net_ratelimited_function(function, ...) \
do { \
if (net_ratelimit()) \
diff --git a/net/socket.c b/net/socket.c
index abf56b2a14f9..f254e9bf9c4d 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -96,6 +96,7 @@
#include <net/compat.h>
#include <net/wext.h>
#include <net/cls_cgroup.h>
+#include <net/sctp/sctp.h>

#include <net/sock.h>
#include <linux/netfilter.h>
@@ -418,6 +419,106 @@ struct socket *sock_from_file(struct file *file, int *err)
}
EXPORT_SYMBOL(sock_from_file);

+static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
+{
+ struct fd f = fdget(fd);
+ struct socket *sock;
+
+ *err = -EBADF;
+ if (f.file) {
+ sock = sock_from_file(f.file, err);
+ if (likely(sock)) {
+ *fput_needed = f.flags;
+ return sock;
+ }
+ fdput(f);
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_SECURITY_CAPSICUM
+struct socket *sockfd_lookup_rights(int fd, int *err,
+ struct capsicum_rights *rights)
+{
+ struct file *file;
+ struct socket *sock;
+
+ file = fget_rights(fd, rights);
+ if (IS_ERR(file)) {
+ *err = PTR_ERR(file);
+ return NULL;
+ }
+
+ sock = sock_from_file(file, err);
+ if (!sock)
+ fput(file);
+ return sock;
+}
+EXPORT_SYMBOL(sockfd_lookup_rights);
+
+static struct socket *
+sockfd_lookup_light_rights(int fd, int *err, int *fput_needed,
+ const struct capsicum_rights **actual_rights,
+ const struct capsicum_rights *required_rights)
+{
+ struct fd f = fdget_raw_rights(fd, actual_rights, required_rights);
+ struct socket *sock;
+
+ *err = -EBADF;
+ if (!IS_ERR(f.file)) {
+ sock = sock_from_file(f.file, err);
+ if (likely(sock)) {
+ *fput_needed = f.flags;
+ return sock;
+ }
+ fdput(f);
+ } else {
+ *err = PTR_ERR(f.file);
+ }
+ return NULL;
+}
+
+struct socket *_sockfd_lookupr(int fd, int *err, ...)
+{
+ struct capsicum_rights rights;
+ struct socket *sock;
+ va_list ap;
+ va_start(ap, err);
+ sock = sockfd_lookup_rights(fd, err, cap_rights_vinit(&rights, ap));
+ va_end(ap);
+ return sock;
+}
+EXPORT_SYMBOL(_sockfd_lookupr);
+
+struct socket *_sockfd_lookupr_light(int fd, int *err, int *fput_needed, ...)
+{
+ struct capsicum_rights rights;
+ struct socket *sock;
+ va_list ap;
+ va_start(ap, fput_needed);
+ sock = sockfd_lookup_light_rights(fd, err, fput_needed,
+ NULL, cap_rights_vinit(&rights, ap));
+ va_end(ap);
+ return sock;
+}
+#define sockfd_lookupr_light(fd, err, fpn, ...) \
+ _sockfd_lookupr_light((fd), (err), (fpn), __VA_ARGS__, 0ULL)
+
+#else
+
+static inline struct socket *
+sockfd_lookup_light_rights(int fd, int *err, int *fput_needed,
+ const struct capsicum_rights **actual_rights,
+ const struct capsicum_rights *required_rights)
+{
+ return sockfd_lookup_light(fd, err, fput_needed);
+}
+
+#define sockfd_lookupr_light(f, e, p, ...) \
+ sockfd_lookup_light((f), (e), (p))
+
+#endif
+
/**
* sockfd_lookup - Go from a file number to its socket slot
* @fd: file handle
@@ -449,23 +550,6 @@ struct socket *sockfd_lookup(int fd, int *err)
}
EXPORT_SYMBOL(sockfd_lookup);

-static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
-{
- struct fd f = fdget(fd);
- struct socket *sock;
-
- *err = -EBADF;
- if (f.file) {
- sock = sock_from_file(f.file, err);
- if (likely(sock)) {
- *fput_needed = f.flags;
- return sock;
- }
- fdput(f);
- }
- return NULL;
-}
-
#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
--
2.0.0.526.g5318336

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/