Signed-off-by: John Johansen <[EMAIL PROTECTED]>
Signed-off-by: Jesse Michael <[EMAIL PROTECTED]>

---
 security/apparmor/Makefile           |    7 +
 security/apparmor/apparmor.h         |    7 +
 security/apparmor/lsm.c              |  129 ++++++++++++++++++++++++++++++++++-
 security/apparmor/main.c             |   96 ++++++++++++++++++++++++++
 security/apparmor/module_interface.c |   20 +++++
 5 files changed, 255 insertions(+), 4 deletions(-)

--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -8,6 +8,11 @@ apparmor-y := main.o list.o procattr.o l
 quiet_cmd_make-caps = GEN     $@
 cmd_make-caps = sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ 
\\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2]  = \"\\1\",/p" $< 
| tr A-Z a-z > $@
 
-$(obj)/main.o : $(obj)/capability_names.h
+quiet_cmd_make-af = GEN     $@
+cmd_make-af = sed -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "s/^\#define[ 
\\t]\\+AF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2]  = 
\"\\1\",/p" $< | tr A-Z a-z > $@
+
+$(obj)/main.o : $(obj)/capability_names.h $(obj)/af_names.h
 $(obj)/capability_names.h : $(srctree)/include/linux/capability.h
        $(call cmd,make-caps)
+$(obj)/af_names.h : $(srctree)/include/linux/socket.h
+       $(call cmd,make-af)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -16,6 +16,8 @@
 #include <linux/fs.h>
 #include <linux/binfmts.h>
 #include <linux/rcupdate.h>
+#include <linux/socket.h>
+#include <net/sock.h>
 
 /*
  * We use MAY_READ, MAY_WRITE, MAY_EXEC, MAY_APPEND and the following flags
@@ -169,6 +171,7 @@ struct aa_profile {
        struct list_head task_contexts;
        spinlock_t lock;
        unsigned long int_flags;
+       u16 network_families[AF_MAX];
 };
 
 extern struct list_head profile_ns_list;
@@ -215,6 +218,7 @@ struct aa_audit {
        int request_mask, denied_mask;
        struct iattr *iattr;
        pid_t task, parent;
+       int family, type, protocol;
        int error_code;
 };
 
@@ -276,6 +280,9 @@ extern void aa_change_task_context(struc
                                   struct aa_profile *previous_profile);
 extern int aa_may_ptrace(struct aa_task_context *cxt,
                         struct aa_profile *tracee);
+extern int aa_net_perm(struct aa_profile *profile, char *operation,
+                       int family, int type, int protocol);
+extern int aa_revalidate_sk(struct sock *sk, char *operation);
 
 /* list.c */
 extern struct aa_namespace *__aa_find_namespace(const char *name,
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -18,6 +18,7 @@
 #include <linux/ctype.h>
 #include <linux/sysctl.h>
 #include <linux/audit.h>
+#include <net/sock.h>
 
 #include "apparmor.h"
 #include "inline.h"
@@ -616,6 +617,117 @@ static void apparmor_task_free_security(
        aa_release(task);
 }
 
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+       struct aa_profile *profile;
+       int error = 0;
+
+       if (kern)
+               return 0;
+
+       profile = aa_get_profile(current);
+       if (profile)
+               error = aa_net_perm(profile, "socket_create", family,
+                                                       type, protocol);
+       aa_put_profile(profile);
+
+       return error;
+}
+
+static int apparmor_socket_post_create(struct socket *sock, int family,
+                                       int type, int protocol, int kern)
+{
+       struct sock *sk = sock->sk;
+
+       if (kern)
+               return 0;
+
+       return aa_revalidate_sk(sk, "socket_post_create");
+}
+
+static int apparmor_socket_bind(struct socket *sock,
+                               struct sockaddr *address, int addrlen)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_bind");
+}
+
+static int apparmor_socket_connect(struct socket *sock,
+                                       struct sockaddr *address, int addrlen)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_connect");
+}
+
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_listen");
+}
+
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_accept");
+}
+
+static int apparmor_socket_sendmsg(struct socket *sock,
+                                       struct msghdr *msg, int size)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_sendmsg");
+}
+
+static int apparmor_socket_recvmsg(struct socket *sock,
+                                  struct msghdr *msg, int size, int flags)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_recvmsg");
+}
+
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_getsockname");
+}
+
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_getpeername");
+}
+
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+                                       int optname)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_getsockopt");
+}
+
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+                                       int optname)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_setsockopt");
+}
+
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+       struct sock *sk = sock->sk;
+
+       return aa_revalidate_sk(sk, "socket_shutdown");
+}
+
 static int apparmor_getprocattr(struct task_struct *task, char *name,
                                char **value)
 {
@@ -716,9 +828,6 @@ struct security_operations apparmor_ops 
        .capable =                      apparmor_capable,
        .syslog =                       cap_syslog,
 
-       .netlink_send =                 cap_netlink_send,
-       .netlink_recv =                 cap_netlink_recv,
-
        .bprm_apply_creds =             cap_bprm_apply_creds,
        .bprm_set_security =            apparmor_bprm_set_security,
        .bprm_secureexec =              apparmor_bprm_secureexec,
@@ -754,6 +863,20 @@ struct security_operations apparmor_ops 
 
        .getprocattr =                  apparmor_getprocattr,
        .setprocattr =                  apparmor_setprocattr,
+
+       .socket_create =                apparmor_socket_create,
+       .socket_post_create =           apparmor_socket_post_create,
+       .socket_bind =                  apparmor_socket_bind,
+       .socket_connect =               apparmor_socket_connect,
+       .socket_listen =                apparmor_socket_listen,
+       .socket_accept =                apparmor_socket_accept,
+       .socket_sendmsg =               apparmor_socket_sendmsg,
+       .socket_recvmsg =               apparmor_socket_recvmsg,
+       .socket_getsockname =           apparmor_socket_getsockname,
+       .socket_getpeername =           apparmor_socket_getpeername,
+       .socket_getsockopt =            apparmor_socket_getsockopt,
+       .socket_setsockopt =            apparmor_socket_setsockopt,
+       .socket_shutdown =              apparmor_socket_shutdown,
 };
 
 static void info_message(const char *str)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -14,6 +14,9 @@
 #include <linux/audit.h>
 #include <linux/mount.h>
 #include <linux/ptrace.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <net/sock.h>
 
 #include "apparmor.h"
 
@@ -341,6 +344,24 @@ static void aa_audit_file_mask(struct au
        audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
 }
 
+static const char *address_families[] = {
+#include "af_names.h"
+};
+
+static const char *sock_types[] = {
+       "unknown(0)",
+       "stream",
+       "dgram",
+       "raw",
+       "rdm",
+       "seqpacket",
+       "dccp",
+       "unknown(7)",
+       "unknown(8)",
+       "unknown(9)",
+       "packet",
+};
+
 /**
  * aa_audit - Log an audit event to the audit subsystem
  * @profile: profile to check against
@@ -406,6 +427,24 @@ static int aa_audit_base(struct aa_profi
                audit_log_untrustedstring(ab, sa->name2);
        }
 
+       if (sa->family || sa->type) {
+               if (address_families[sa->family])
+                       audit_log_format(ab, " family=\"%s\"",
+                                        address_families[sa->family]);
+               else
+                       audit_log_format(ab, " family=\"unknown(%d)\"",
+                                        sa->family);
+
+               if (sock_types[sa->type])
+                       audit_log_format(ab, " sock_type=\"%s\"",
+                                        sock_types[sa->type]);
+               else
+                       audit_log_format(ab, " sock_type=\"unknown(%d)\"",
+                                        sa->type);
+
+               audit_log_format(ab, " protocol=%d", sa->protocol);
+       }
+
        audit_log_format(ab, " pid=%d", current->pid);
 
        if (profile) {
@@ -725,6 +764,63 @@ int aa_link(struct aa_profile *profile,
        return error;
 }
 
+int aa_net_perm(struct aa_profile *profile, char *operation,
+               int family, int type, int protocol)
+{
+       struct aa_audit sa;
+       int error = 0;
+       u16 family_mask;
+
+       if ((family < 0) || (family >= AF_MAX))
+               return -EINVAL;
+
+       if ((type < 0) || (type >= SOCK_MAX))
+               return -EINVAL;
+
+       /* unix domain and netlink sockets are handled by ipc */
+       if (family == AF_UNIX || family == AF_NETLINK)
+               return 0;
+
+       family_mask = profile->network_families[family];
+
+       error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.operation = operation;
+       sa.gfp_mask = GFP_KERNEL;
+       sa.family = family;
+       sa.type = type;
+       sa.protocol = protocol;
+       sa.error_code = error;
+
+       error = aa_audit(profile, &sa);
+
+       return error;
+}
+
+int aa_revalidate_sk(struct sock *sk, char *operation)
+{
+       struct aa_profile *profile;
+       int error = 0;
+
+       /* this is some debugging code to flush out the network hooks that
+          that are called in interrupt context */
+       if (in_interrupt()) {
+               printk("AppArmor Debug: Hook being called from interrupt 
context\n");
+               dump_stack();
+               return 0;
+       }
+
+       profile = aa_get_profile(current);
+       if (profile)
+               error = aa_net_perm(profile, operation,
+                                   sk->sk_family, sk->sk_type,
+                                   sk->sk_protocol);
+       aa_put_profile(profile);
+
+       return error;
+}
+
 /*******************************
  * Global task related functions
  *******************************/
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -283,6 +283,8 @@ static struct aa_profile *aa_unpack_prof
 {
        struct aa_profile *profile = NULL;
        struct aa_audit sa;
+       size_t size = 0;
+       int i;
 
        int error = -EPROTO;
 
@@ -311,6 +313,24 @@ static struct aa_profile *aa_unpack_prof
        if (!aa_is_u32(e, &(profile->capabilities), NULL))
                goto fail;
 
+       size = aa_is_array(e, "net_allowed_af");
+       if (size) {
+               if (size > AF_MAX)
+                       goto fail;
+
+               for (i = 0; i < size; i++) {
+                       if (!aa_is_u16(e, &profile->network_families[i], NULL))
+                               goto fail;
+               }
+               if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
+                       goto fail;
+               /* allow unix domain and netlink sockets they are handled
+                * by IPC
+                */
+       }
+       profile->network_families[AF_UNIX] = 0xffff;
+       profile->network_families[AF_NETLINK] = 0xffff;
+
        /* get file rules */
        profile->file_rules = aa_unpack_dfa(e);
        if (IS_ERR(profile->file_rules)) {

-- 

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

Reply via email to