linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / security / selinux / hooks.c
index 0b32f30..b65c201 100644 (file)
@@ -18,6 +18,7 @@
  *      as published by the Free Software Foundation.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -68,7 +69,6 @@
 #include <linux/sysctl.h>
 #include <linux/audit.h>
 #include <linux/string.h>
-#include <linux/selinux.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -80,7 +80,6 @@
 
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
-extern int selinux_compat_net;
 
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 int selinux_enforcing = 0;
@@ -102,8 +101,6 @@ static int __init selinux_enabled_setup(char *str)
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
-#else
-int selinux_enabled = 1;
 #endif
 
 /* Original (dummy) security module. */
@@ -120,34 +117,6 @@ static struct security_operations *secondary_ops = NULL;
 static LIST_HEAD(superblock_security_head);
 static DEFINE_SPINLOCK(sb_security_lock);
 
-static kmem_cache_t *sel_inode_cache;
-
-/* Return security context for a given sid or just the context 
-   length if the buffer is null or length is 0 */
-static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
-{
-       char *context;
-       unsigned len;
-       int rc;
-
-       rc = security_sid_to_context(sid, &context, &len);
-       if (rc)
-               return rc;
-
-       if (!buffer || !size)
-               goto getsecurity_exit;
-
-       if (size < len) {
-               len = -ERANGE;
-               goto getsecurity_exit;
-       }
-       memcpy(buffer, context, len);
-
-getsecurity_exit:
-       kfree(context);
-       return len;
-}
-
 /* Allocate and free functions for each kind of security blob. */
 
 static int task_alloc_security(struct task_struct *task)
@@ -177,11 +146,10 @@ static int inode_alloc_security(struct inode *inode)
        struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
 
-       isec = kmem_cache_alloc(sel_inode_cache, SLAB_KERNEL);
+       isec = kzalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
        if (!isec)
                return -ENOMEM;
 
-       memset(isec, 0, sizeof(*isec));
        init_MUTEX(&isec->sem);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
@@ -204,7 +172,7 @@ static void inode_free_security(struct inode *inode)
        spin_unlock(&sbsec->isec_lock);
 
        inode->i_security = NULL;
-       kmem_cache_free(sel_inode_cache, isec);
+       kfree(isec);
 }
 
 static int file_alloc_security(struct file *file)
@@ -246,7 +214,6 @@ static int superblock_alloc_security(struct super_block *sb)
        sbsec->sb = sb;
        sbsec->sid = SECINITSID_UNLABELED;
        sbsec->def_sid = SECINITSID_FILE;
-       sbsec->mntpoint_sid = SECINITSID_UNLABELED;
        sb->s_security = sbsec;
 
        return 0;
@@ -320,53 +287,19 @@ enum {
        Opt_context = 1,
        Opt_fscontext = 2,
        Opt_defcontext = 4,
-       Opt_rootcontext = 8,
 };
 
 static match_table_t tokens = {
        {Opt_context, "context=%s"},
        {Opt_fscontext, "fscontext=%s"},
        {Opt_defcontext, "defcontext=%s"},
-       {Opt_rootcontext, "rootcontext=%s"},
 };
 
 #define SEL_MOUNT_FAIL_MSG "SELinux:  duplicate or incompatible mount options\n"
 
-static int may_context_mount_sb_relabel(u32 sid,
-                       struct superblock_security_struct *sbsec,
-                       struct task_security_struct *tsec)
-{
-       int rc;
-
-       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                         FILESYSTEM__RELABELFROM, NULL);
-       if (rc)
-               return rc;
-
-       rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
-                         FILESYSTEM__RELABELTO, NULL);
-       return rc;
-}
-
-static int may_context_mount_inode_relabel(u32 sid,
-                       struct superblock_security_struct *sbsec,
-                       struct task_security_struct *tsec)
-{
-       int rc;
-       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                         FILESYSTEM__RELABELFROM, NULL);
-       if (rc)
-               return rc;
-
-       rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                         FILESYSTEM__ASSOCIATE, NULL);
-       return rc;
-}
-
 static int try_context_mount(struct super_block *sb, void *data)
 {
        char *context = NULL, *defcontext = NULL;
-       char *fscontext = NULL, *rootcontext = NULL;
        const char *name;
        u32 sid;
        int alloc = 0, rc = 0, seen = 0;
@@ -409,7 +342,7 @@ static int try_context_mount(struct super_block *sb, void *data)
 
                        switch (token) {
                        case Opt_context:
-                               if (seen & (Opt_context|Opt_defcontext)) {
+                               if (seen) {
                                        rc = -EINVAL;
                                        printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
                                        goto out_free;
@@ -425,13 +358,13 @@ static int try_context_mount(struct super_block *sb, void *data)
                                break;
 
                        case Opt_fscontext:
-                               if (seen & Opt_fscontext) {
+                               if (seen & (Opt_context|Opt_fscontext)) {
                                        rc = -EINVAL;
                                        printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
                                        goto out_free;
                                }
-                               fscontext = match_strdup(&args[0]);
-                               if (!fscontext) {
+                               context = match_strdup(&args[0]);
+                               if (!context) {
                                        rc = -ENOMEM;
                                        goto out_free;
                                }
@@ -440,22 +373,6 @@ static int try_context_mount(struct super_block *sb, void *data)
                                seen |= Opt_fscontext;
                                break;
 
-                       case Opt_rootcontext:
-                               if (seen & Opt_rootcontext) {
-                                       rc = -EINVAL;
-                                       printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
-                                       goto out_free;
-                               }
-                               rootcontext = match_strdup(&args[0]);
-                               if (!rootcontext) {
-                                       rc = -ENOMEM;
-                                       goto out_free;
-                               }
-                               if (!alloc)
-                                       alloc = 1;
-                               seen |= Opt_rootcontext;
-                               break;
-
                        case Opt_defcontext:
                                if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
                                        rc = -EINVAL;
@@ -492,28 +409,6 @@ static int try_context_mount(struct super_block *sb, void *data)
        if (!seen)
                goto out;
 
-       /* sets the context of the superblock for the fs being mounted. */
-       if (fscontext) {
-               rc = security_context_to_sid(fscontext, strlen(fscontext), &sid);
-               if (rc) {
-                       printk(KERN_WARNING "SELinux: security_context_to_sid"
-                              "(%s) failed for (dev %s, type %s) errno=%d\n",
-                              fscontext, sb->s_id, name, rc);
-                       goto out_free;
-               }
-
-               rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
-               if (rc)
-                       goto out_free;
-
-               sbsec->sid = sid;
-       }
-
-       /*
-        * Switch to using mount point labeling behavior.
-        * sets the label used on all file below the mountpoint, and will set
-        * the superblock context if not already set.
-        */
        if (context) {
                rc = security_context_to_sid(context, strlen(context), &sid);
                if (rc) {
@@ -523,38 +418,20 @@ static int try_context_mount(struct super_block *sb, void *data)
                        goto out_free;
                }
 
-               if (!fscontext) {
-                       rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
-                       if (rc)
-                               goto out_free;
-                       sbsec->sid = sid;
-               } else {
-                       rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
-                       if (rc)
-                               goto out_free;
-               }
-               sbsec->mntpoint_sid = sid;
-
-               sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
-       }
-
-       if (rootcontext) {
-               struct inode *inode = sb->s_root->d_inode;
-               struct inode_security_struct *isec = inode->i_security;
-               rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid);
-               if (rc) {
-                       printk(KERN_WARNING "SELinux: security_context_to_sid"
-                              "(%s) failed for (dev %s, type %s) errno=%d\n",
-                              rootcontext, sb->s_id, name, rc);
+               rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+                                 FILESYSTEM__RELABELFROM, NULL);
+               if (rc)
                        goto out_free;
-               }
 
-               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+               rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
+                                 FILESYSTEM__RELABELTO, NULL);
                if (rc)
                        goto out_free;
 
-               isec->sid = sid;
-               isec->initialized = 1;
+               sbsec->sid = sid;
+
+               if (seen & Opt_context)
+                       sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
        }
 
        if (defcontext) {
@@ -569,7 +446,13 @@ static int try_context_mount(struct super_block *sb, void *data)
                if (sid == sbsec->def_sid)
                        goto out_free;
 
-               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+               rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+                                 FILESYSTEM__RELABELFROM, NULL);
+               if (rc)
+                       goto out_free;
+
+               rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
+                                 FILESYSTEM__ASSOCIATE, NULL);
                if (rc)
                        goto out_free;
 
@@ -580,8 +463,6 @@ out_free:
        if (alloc) {
                kfree(context);
                kfree(defcontext);
-               kfree(fscontext);
-               kfree(rootcontext);
        }
 out:
        return rc;
@@ -784,8 +665,6 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                return SECCLASS_PACKET_SOCKET;
        case PF_KEY:
                return SECCLASS_KEY_SOCKET;
-       case PF_APPLETALK:
-               return SECCLASS_APPLETALK_SOCKET;
        }
 
        return SECCLASS_SOCKET;
@@ -963,11 +842,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        goto out;
                isec->sid = sid;
                break;
-       case SECURITY_FS_USE_MNTPOINT:
-               isec->sid = sbsec->mntpoint_sid;
-               break;
        default:
-               /* Default to the fs superblock SID. */
+               /* Default to the fs SID. */
                isec->sid = sbsec->sid;
 
                if (sbsec->proc) {
@@ -1189,17 +1065,6 @@ static int may_create(struct inode *dir,
                            FILESYSTEM__ASSOCIATE, &ad);
 }
 
-/* Check whether a task can create a key. */
-static int may_create_key(u32 ksid,
-                         struct task_struct *ctx)
-{
-       struct task_security_struct *tsec;
-
-       tsec = ctx->security;
-
-       return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
-}
-
 #define MAY_LINK   0
 #define MAY_UNLINK 1
 #define MAY_RMDIR  2
@@ -1622,10 +1487,8 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        /* Default to the current task SID. */
        bsec->sid = tsec->sid;
 
-       /* Reset fs, key, and sock SIDs on execve. */
+       /* Reset create SID on execve. */
        tsec->create_sid = 0;
-       tsec->keycreate_sid = 0;
-       tsec->sockcreate_sid = 0;
 
        if (tsec->exec_sid) {
                newsid = tsec->exec_sid;
@@ -1711,13 +1574,10 @@ static inline void flush_unauthorized_files(struct files_struct * files)
 {
        struct avc_audit_data ad;
        struct file *file, *devnull = NULL;
-       struct tty_struct *tty;
+       struct tty_struct *tty = current->signal->tty;
        struct fdtable *fdt;
        long j = -1;
-       int drop_tty = 0;
 
-       mutex_lock(&tty_mutex);
-       tty = get_current_tty();
        if (tty) {
                file_list_lock();
                file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
@@ -1730,16 +1590,13 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                        struct inode *inode = file->f_dentry->d_inode;
                        if (inode_has_perm(current, inode,
                                           FILE__READ | FILE__WRITE, NULL)) {
-                               drop_tty = 1;
+                               /* Reset controlling tty. */
+                               current->signal->tty = NULL;
+                               current->signal->tty_old_pgrp = 0;
                        }
                }
                file_list_unlock();
-
-               /* Reset controlling tty. */
-               if (drop_tty)
-                       proc_set_tty(current, NULL);
        }
-       mutex_unlock(&tty_mutex);
 
        /* Revalidate access to inherited open files. */
 
@@ -1939,8 +1796,7 @@ static inline int selinux_option(char *option, int len)
 {
        return (match_prefix("context=", sizeof("context=")-1, option, len) ||
                match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) ||
-               match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) ||
-               match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len));
+               match_prefix("defcontext=", sizeof("defcontext=")-1, option, len));
 }
 
 static inline void take_option(char **to, char *from, int *first, int len)
@@ -2013,13 +1869,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
        return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
 }
 
-static int selinux_sb_statfs(struct dentry *dentry)
+static int selinux_sb_statfs(struct super_block *sb)
 {
        struct avc_audit_data ad;
 
        AVC_AUDIT_DATA_INIT(&ad,FS);
-       ad.u.fs.dentry = dentry->d_sb->s_root;
-       return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
+       ad.u.fs.dentry = sb->s_root;
+       return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad);
 }
 
 static int selinux_mount(char * dev_name,
@@ -2073,6 +1929,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        struct task_security_struct *tsec;
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
+       struct inode_security_struct *isec;
        u32 newsid, clen;
        int rc;
        char *namep = NULL, *context;
@@ -2080,6 +1937,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        tsec = current->security;
        dsec = dir->i_security;
        sbsec = dir->i_sb->s_security;
+       isec = inode->i_security;
 
        if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
                newsid = tsec->create_sid;
@@ -2099,7 +1957,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 
        inode_security_set_sid(inode, newsid);
 
-       if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
                return -EOPNOTSUPP;
 
        if (name) {
@@ -2351,11 +2209,6 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
        return -EACCES;
 }
 
-static const char *selinux_inode_xattr_getsuffix(void)
-{
-      return XATTR_SELINUX_SUFFIX;
-}
-
 /*
  * Copy the in-core inode security context value to the user.  If the
  * getxattr() prior to this succeeded, check to see if we need to
@@ -2363,14 +2216,47 @@ static const char *selinux_inode_xattr_getsuffix(void)
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
-static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
        struct inode_security_struct *isec = inode->i_security;
+       char *context;
+       unsigned len;
+       int rc;
 
-       if (strcmp(name, XATTR_SELINUX_SUFFIX))
-               return -EOPNOTSUPP;
+       if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
+               rc = -EOPNOTSUPP;
+               goto out;
+       }
 
-       return selinux_getsecurity(isec->sid, buffer, size);
+       rc = security_sid_to_context(isec->sid, &context, &len);
+       if (rc)
+               goto out;
+
+       /* Probe for required buffer size */
+       if (!buffer || !size) {
+               rc = len;
+               goto out_free;
+       }
+
+       if (size < len) {
+               rc = -ERANGE;
+               goto out_free;
+       }
+
+       if (err > 0) {
+               if ((len == err) && !(memcmp(context, buffer, len))) {
+                       /* Don't need to canonicalize value */
+                       rc = err;
+                       goto out_free;
+               }
+               memset(buffer, 0, size);
+       }
+       memcpy(buffer, context, len);
+       rc = len;
+out_free:
+       kfree(context);
+out:
+       return rc;
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
@@ -2479,6 +2365,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
+#ifndef CONFIG_PPC32
        if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
                /*
                 * We are making executable an anonymous mapping or a
@@ -2489,6 +2376,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
                if (rc)
                        return rc;
        }
+#endif
 
        if (file) {
                /* read access is always possible with a mapping */
@@ -2535,6 +2423,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
        if (selinux_checkreqprot)
                prot = reqprot;
 
+#ifndef CONFIG_PPC32
        if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
                rc = 0;
                if (vma->vm_start >= vma->vm_mm->start_brk &&
@@ -2559,6 +2448,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                if (rc)
                        return rc;
        }
+#endif
 
        return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
 }
@@ -2680,11 +2570,9 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
        tsec2->osid = tsec1->osid;
        tsec2->sid = tsec1->sid;
 
-       /* Retain the exec, fs, key, and sock SIDs across fork */
+       /* Retain the exec and create SIDs across fork */
        tsec2->exec_sid = tsec1->exec_sid;
        tsec2->create_sid = tsec1->create_sid;
-       tsec2->keycreate_sid = tsec1->keycreate_sid;
-       tsec2->sockcreate_sid = tsec1->sockcreate_sid;
 
        /* Retain ptracer SID across fork, if any.
           This will be reset by the ptrace hook upon any
@@ -2736,11 +2624,6 @@ static int selinux_task_getsid(struct task_struct *p)
        return task_has_perm(current, p, PROCESS__GETSESSION);
 }
 
-static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
-{
-       selinux_get_task_sid(p, secid);
-}
-
 static int selinux_task_setgroups(struct group_info *group_info)
 {
        /* See the comment for setuid above. */
@@ -2758,16 +2641,6 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
        return task_has_perm(current,p, PROCESS__SETSCHED);
 }
 
-static int selinux_task_setioprio(struct task_struct *p, int ioprio)
-{
-       return task_has_perm(current, p, PROCESS__SETSCHED);
-}
-
-static int selinux_task_getioprio(struct task_struct *p)
-{
-       return task_has_perm(current, p, PROCESS__GETSCHED);
-}
-
 static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
 {
        struct rlimit *old_rlim = current->signal->rlim + resource;
@@ -2797,19 +2670,12 @@ static int selinux_task_getscheduler(struct task_struct *p)
        return task_has_perm(current, p, PROCESS__GETSCHED);
 }
 
-static int selinux_task_movememory(struct task_struct *p)
-{
-       return task_has_perm(current, p, PROCESS__SETSCHED);
-}
-
-static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
-                               int sig, u32 secid)
+static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
 {
        u32 perm;
        int rc;
-       struct task_security_struct *tsec;
 
-       rc = secondary_ops->task_kill(p, info, sig, secid);
+       rc = secondary_ops->task_kill(p, info, sig);
        if (rc)
                return rc;
 
@@ -2820,12 +2686,8 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
                perm = signal_to_av(sig);
-       tsec = p->security;
-       if (secid)
-               rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
-       else
-               rc = task_has_perm(current, p, perm);
-       return rc;
+
+       return task_has_perm(current, p, perm);
 }
 
 static int selinux_task_prctl(int option,
@@ -3050,14 +2912,12 @@ static int selinux_socket_create(int family, int type,
 {
        int err = 0;
        struct task_security_struct *tsec;
-       u32 newsid;
 
        if (kern)
                goto out;
 
        tsec = current->security;
-       newsid = tsec->sockcreate_sid ? : tsec->sid;
-       err = avc_has_perm(tsec->sid, newsid,
+       err = avc_has_perm(tsec->sid, tsec->sid,
                           socket_type_to_security_class(family, type,
                           protocol), SOCKET__CREATE, NULL);
 
@@ -3070,14 +2930,12 @@ static void selinux_socket_post_create(struct socket *sock, int family,
 {
        struct inode_security_struct *isec;
        struct task_security_struct *tsec;
-       u32 newsid;
 
        isec = SOCK_INODE(sock)->i_security;
 
        tsec = current->security;
-       newsid = tsec->sockcreate_sid ? : tsec->sid;
        isec->sclass = socket_type_to_security_class(family, type, protocol);
-       isec->sid = kern ? SECINITSID_KERNEL : newsid;
+       isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
        isec->initialized = 1;
 
        return;
@@ -3355,17 +3213,47 @@ static int selinux_socket_unix_may_send(struct socket *sock,
        return 0;
 }
 
-static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
-               struct avc_audit_data *ad, u32 sock_sid, u16 sock_class,
-               u16 family, char *addrp, int len)
+static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-       int err = 0;
+       u16 family;
+       char *addrp;
+       int len, err = 0;
        u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0;
+       u32 sock_sid = 0;
+       u16 sock_class = 0;
+       struct socket *sock;
+       struct net_device *dev;
+       struct avc_audit_data ad;
+
+       family = sk->sk_family;
+       if (family != PF_INET && family != PF_INET6)
+               goto out;
+
+       /* Handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
+               family = PF_INET;
+
+       read_lock_bh(&sk->sk_callback_lock);
+       sock = sk->sk_socket;
+       if (sock) {
+               struct inode *inode;
+               inode = SOCK_INODE(sock);
+               if (inode) {
+                       struct inode_security_struct *isec;
+                       isec = inode->i_security;
+                       sock_sid = isec->sid;
+                       sock_class = isec->sclass;
+               }
+       }
+       read_unlock_bh(&sk->sk_callback_lock);
+       if (!sock_sid)
+               goto out;
 
-       if (!skb->dev)
+       dev = skb->dev;
+       if (!dev)
                goto out;
 
-       err = sel_netif_sids(skb->dev, &if_sid, NULL);
+       err = sel_netif_sids(dev, &if_sid, NULL);
        if (err)
                goto out;
 
@@ -3388,124 +3276,66 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                break;
        }
 
-       err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = dev->name;
+       ad.u.net.family = family;
+
+       err = selinux_parse_skb(skb, &ad, &addrp, &len, 1);
+       if (err)
+               goto out;
+
+       err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, &ad);
        if (err)
                goto out;
        
+       /* Fixme: this lookup is inefficient */
        err = security_node_sid(family, addrp, len, &node_sid);
        if (err)
                goto out;
        
-       err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad);
+       err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, &ad);
        if (err)
                goto out;
 
        if (recv_perm) {
                u32 port_sid;
 
+               /* Fixme: make this more efficient */
                err = security_port_sid(sk->sk_family, sk->sk_type,
-                                       sk->sk_protocol, ntohs(ad->u.net.sport),
+                                       sk->sk_protocol, ntohs(ad.u.net.sport),
                                        &port_sid);
                if (err)
                        goto out;
 
                err = avc_has_perm(sock_sid, port_sid,
-                                  sock_class, recv_perm, ad);
+                                  sock_class, recv_perm, &ad);
        }
 
-out:
-       return err;
-}
-
-static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
-{
-       u16 family;
-       u16 sock_class = 0;
-       char *addrp;
-       int len, err = 0;
-       u32 sock_sid = 0;
-       struct socket *sock;
-       struct avc_audit_data ad;
-
-       family = sk->sk_family;
-       if (family != PF_INET && family != PF_INET6)
-               goto out;
+       if (!err)
+               err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
 
-       /* Handle mapped IPv4 packets arriving via IPv6 sockets */
-       if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
-               family = PF_INET;
-
-       read_lock_bh(&sk->sk_callback_lock);
-       sock = sk->sk_socket;
-       if (sock) {
-               struct inode *inode;
-               inode = SOCK_INODE(sock);
-               if (inode) {
-                       struct inode_security_struct *isec;
-                       isec = inode->i_security;
-                       sock_sid = isec->sid;
-                       sock_class = isec->sclass;
-               }
-       }
-       read_unlock_bh(&sk->sk_callback_lock);
-       if (!sock_sid)
-               goto out;
-
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]";
-       ad.u.net.family = family;
-
-       err = selinux_parse_skb(skb, &ad, &addrp, &len, 1);
-       if (err)
-               goto out;
-
-       if (selinux_compat_net)
-               err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid,
-                                                 sock_class, family,
-                                                 addrp, len);
-       else
-               err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET,
-                                  PACKET__RECV, &ad);
-       if (err)
-               goto out;
-
-       err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
 out:   
        return err;
 }
 
-static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
-                                           int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
+                                    int __user *optlen, unsigned len)
 {
        int err = 0;
        char *scontext;
        u32 scontext_len;
        struct sk_security_struct *ssec;
        struct inode_security_struct *isec;
-       u32 peer_sid = 0;
 
        isec = SOCK_INODE(sock)->i_security;
-
-       /* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */
-       if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) {
-               ssec = sock->sk->sk_security;
-               peer_sid = ssec->peer_sid;
-       }
-       else if (isec->sclass == SECCLASS_TCP_SOCKET) {
-               peer_sid = selinux_socket_getpeer_stream(sock->sk);
-
-               if (peer_sid == SECSID_NULL) {
-                       err = -ENOPROTOOPT;
-                       goto out;
-               }
-       }
-       else {
+       if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
                err = -ENOPROTOOPT;
                goto out;
        }
 
-       err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
-
+       ssec = sock->sk->sk_security;
+       
+       err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
        if (err)
                goto out;
 
@@ -3526,23 +3356,6 @@ out:
        return err;
 }
 
-static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
-{
-       u32 peer_secid = SECSID_NULL;
-       int err = 0;
-
-       if (sock && (sock->sk->sk_family == PF_UNIX))
-               selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
-       else if (skb)
-               peer_secid = selinux_socket_getpeer_dgram(skb);
-
-       if (peer_secid == SECSID_NULL)
-               err = -EINVAL;
-       *secid = peer_secid;
-
-       return err;
-}
-
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
        return sk_alloc_security(sk, family, priority);
@@ -3609,18 +3422,42 @@ out:
 
 #ifdef CONFIG_NETFILTER
 
-static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev,
-                                           struct inode_security_struct *isec,
-                                           struct avc_audit_data *ad,
-                                           u16 family, char *addrp, int len)
+static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
+                                              struct sk_buff **pskb,
+                                              const struct net_device *in,
+                                              const struct net_device *out,
+                                              int (*okfn)(struct sk_buff *),
+                                              u16 family)
 {
-       int err;
+       char *addrp;
+       int len, err = NF_ACCEPT;
        u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0;
+       struct sock *sk;
+       struct socket *sock;
+       struct inode *inode;
+       struct sk_buff *skb = *pskb;
+       struct inode_security_struct *isec;
+       struct avc_audit_data ad;
+       struct net_device *dev = (struct net_device *)out;
        
+       sk = skb->sk;
+       if (!sk)
+               goto out;
+               
+       sock = sk->sk_socket;
+       if (!sock)
+               goto out;
+               
+       inode = SOCK_INODE(sock);
+       if (!inode)
+               goto out;
+
        err = sel_netif_sids(dev, &if_sid, NULL);
        if (err)
                goto out;
 
+       isec = inode->i_security;
+       
        switch (isec->sclass) {
        case SECCLASS_UDP_SOCKET:
                netif_perm = NETIF__UDP_SEND;
@@ -3640,88 +3477,55 @@ static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *
                break;
        }
 
-       err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
-       if (err)
+
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = dev->name;
+       ad.u.net.family = family;
+
+       err = selinux_parse_skb(skb, &ad, &addrp,
+                               &len, 0) ? NF_DROP : NF_ACCEPT;
+       if (err != NF_ACCEPT)
+               goto out;
+
+       err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF,
+                          netif_perm, &ad) ? NF_DROP : NF_ACCEPT;
+       if (err != NF_ACCEPT)
                goto out;
                
-       err = security_node_sid(family, addrp, len, &node_sid);
-       if (err)
+       /* Fixme: this lookup is inefficient */
+       err = security_node_sid(family, addrp, len,
+                               &node_sid) ? NF_DROP : NF_ACCEPT;
+       if (err != NF_ACCEPT)
                goto out;
        
-       err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
-       if (err)
+       err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE,
+                          node_perm, &ad) ? NF_DROP : NF_ACCEPT;
+       if (err != NF_ACCEPT)
                goto out;
 
        if (send_perm) {
                u32 port_sid;
                
+               /* Fixme: make this more efficient */
                err = security_port_sid(sk->sk_family,
                                        sk->sk_type,
                                        sk->sk_protocol,
-                                       ntohs(ad->u.net.dport),
-                                       &port_sid);
-               if (err)
+                                       ntohs(ad.u.net.dport),
+                                       &port_sid) ? NF_DROP : NF_ACCEPT;
+               if (err != NF_ACCEPT)
                        goto out;
 
                err = avc_has_perm(isec->sid, port_sid, isec->sclass,
-                                  send_perm, ad);
+                                  send_perm, &ad) ? NF_DROP : NF_ACCEPT;
        }
-out:
-       return err;
-}
-
-static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
-                                              struct sk_buff **pskb,
-                                              const struct net_device *in,
-                                              const struct net_device *out,
-                                              int (*okfn)(struct sk_buff *),
-                                              u16 family)
-{
-       char *addrp;
-       int len, err = 0;
-       struct sock *sk;
-       struct socket *sock;
-       struct inode *inode;
-       struct sk_buff *skb = *pskb;
-       struct inode_security_struct *isec;
-       struct avc_audit_data ad;
-       struct net_device *dev = (struct net_device *)out;
-
-       sk = skb->sk;
-       if (!sk)
-               goto out;
 
-       sock = sk->sk_socket;
-       if (!sock)
-               goto out;
-
-       inode = SOCK_INODE(sock);
-       if (!inode)
-               goto out;
-
-       isec = inode->i_security;
-
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = dev->name;
-       ad.u.net.family = family;
-
-       err = selinux_parse_skb(skb, &ad, &addrp, &len, 0);
-       if (err)
-               goto out;
-
-       if (selinux_compat_net)
-               err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad,
-                                                      family, addrp, len);
-       else
-               err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET,
-                                  PACKET__SEND, &ad);
-
-       if (err)
+       if (err != NF_ACCEPT)
                goto out;
 
        err = selinux_xfrm_postroute_last(isec->sid, skb);
+
 out:
-       return err ? NF_DROP : NF_ACCEPT;
+       return err;
 }
 
 static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum,
@@ -3750,32 +3554,32 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
 
 static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
+       struct task_security_struct *tsec;
+       struct av_decision avd;
        int err;
 
        err = secondary_ops->netlink_send(sk, skb);
        if (err)
                return err;
 
+       tsec = current->security;
+
+       avd.allowed = 0;
+       avc_has_perm_noaudit(tsec->sid, tsec->sid,
+                               SECCLASS_CAPABILITY, ~0, &avd);
+       cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed);
+
        if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
                err = selinux_nlmsg_perm(sk, skb);
 
        return err;
 }
 
-static int selinux_netlink_recv(struct sk_buff *skb, int capability)
+static int selinux_netlink_recv(struct sk_buff *skb)
 {
-       int err;
-       struct avc_audit_data ad;
-
-       err = secondary_ops->netlink_recv(skb, capability);
-       if (err)
-               return err;
-
-       AVC_AUDIT_DATA_INIT(&ad, CAP);
-       ad.u.cap = capability;
-
-       return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
-                           SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
+       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+               return -EPERM;
+       return 0;
 }
 
 static int ipc_alloc_security(struct task_struct *task,
@@ -4259,7 +4063,8 @@ static int selinux_getprocattr(struct task_struct *p,
                               char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
-       u32 sid;
+       u32 sid, len;
+       char *context;
        int error;
 
        if (current != p) {
@@ -4268,6 +4073,9 @@ static int selinux_getprocattr(struct task_struct *p,
                        return error;
        }
 
+       if (!size)
+               return -ERANGE;
+
        tsec = p->security;
 
        if (!strcmp(name, "current"))
@@ -4278,17 +4086,22 @@ static int selinux_getprocattr(struct task_struct *p,
                sid = tsec->exec_sid;
        else if (!strcmp(name, "fscreate"))
                sid = tsec->create_sid;
-       else if (!strcmp(name, "keycreate"))
-               sid = tsec->keycreate_sid;
-       else if (!strcmp(name, "sockcreate"))
-               sid = tsec->sockcreate_sid;
        else
                return -EINVAL;
 
        if (!sid)
                return 0;
 
-       return selinux_getsecurity(sid, value, size);
+       error = security_sid_to_context(sid, &context, &len);
+       if (error)
+               return error;
+       if (len > size) {
+               kfree(context);
+               return -ERANGE;
+       }
+       memcpy(value, context, len);
+       kfree(context);
+       return len;
 }
 
 static int selinux_setprocattr(struct task_struct *p,
@@ -4314,10 +4127,6 @@ static int selinux_setprocattr(struct task_struct *p,
                error = task_has_perm(current, p, PROCESS__SETEXEC);
        else if (!strcmp(name, "fscreate"))
                error = task_has_perm(current, p, PROCESS__SETFSCREATE);
-       else if (!strcmp(name, "keycreate"))
-               error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
-       else if (!strcmp(name, "sockcreate"))
-               error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
        else if (!strcmp(name, "current"))
                error = task_has_perm(current, p, PROCESS__SETCURRENT);
        else
@@ -4347,13 +4156,6 @@ static int selinux_setprocattr(struct task_struct *p,
                tsec->exec_sid = sid;
        else if (!strcmp(name, "fscreate"))
                tsec->create_sid = sid;
-       else if (!strcmp(name, "keycreate")) {
-               error = may_create_key(sid, p);
-               if (error)
-                       return error;
-               tsec->keycreate_sid = sid;
-       } else if (!strcmp(name, "sockcreate"))
-               tsec->sockcreate_sid = sid;
        else if (!strcmp(name, "current")) {
                struct av_decision avd;
 
@@ -4405,72 +4207,6 @@ static int selinux_setprocattr(struct task_struct *p,
        return size;
 }
 
-static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
-{
-       return security_sid_to_context(secid, secdata, seclen);
-}
-
-static void selinux_release_secctx(char *secdata, u32 seclen)
-{
-       if (secdata)
-               kfree(secdata);
-}
-
-#ifdef CONFIG_KEYS
-
-static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
-                            unsigned long flags)
-{
-       struct task_security_struct *tsec = tsk->security;
-       struct key_security_struct *ksec;
-
-       ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
-       if (!ksec)
-               return -ENOMEM;
-
-       ksec->obj = k;
-       if (tsec->keycreate_sid)
-               ksec->sid = tsec->keycreate_sid;
-       else
-               ksec->sid = tsec->sid;
-       k->security = ksec;
-
-       return 0;
-}
-
-static void selinux_key_free(struct key *k)
-{
-       struct key_security_struct *ksec = k->security;
-
-       k->security = NULL;
-       kfree(ksec);
-}
-
-static int selinux_key_permission(key_ref_t key_ref,
-                           struct task_struct *ctx,
-                           key_perm_t perm)
-{
-       struct key *key;
-       struct task_security_struct *tsec;
-       struct key_security_struct *ksec;
-
-       key = key_ref_to_ptr(key_ref);
-
-       tsec = ctx->security;
-       ksec = key->security;
-
-       /* if no specific permissions are requested, we skip the
-          permission check. No serious, additional covert channels
-          appear to be created. */
-       if (perm == 0)
-               return 0;
-
-       return avc_has_perm(tsec->sid, ksec->sid,
-                           SECCLASS_KEY, perm, NULL);
-}
-
-#endif
-
 static struct security_operations selinux_ops = {
        .ptrace =                       selinux_ptrace,
        .capget =                       selinux_capget,
@@ -4523,7 +4259,6 @@ static struct security_operations selinux_ops = {
        .inode_getxattr =               selinux_inode_getxattr,
        .inode_listxattr =              selinux_inode_listxattr,
        .inode_removexattr =            selinux_inode_removexattr,
-       .inode_xattr_getsuffix =        selinux_inode_xattr_getsuffix,
        .inode_getsecurity =            selinux_inode_getsecurity,
        .inode_setsecurity =            selinux_inode_setsecurity,
        .inode_listsecurity =           selinux_inode_listsecurity,
@@ -4549,15 +4284,11 @@ static struct security_operations selinux_ops = {
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
        .task_getsid =                  selinux_task_getsid,
-       .task_getsecid =                selinux_task_getsecid,
        .task_setgroups =               selinux_task_setgroups,
        .task_setnice =                 selinux_task_setnice,
-       .task_setioprio =               selinux_task_setioprio,
-       .task_getioprio =               selinux_task_getioprio,
        .task_setrlimit =               selinux_task_setrlimit,
        .task_setscheduler =            selinux_task_setscheduler,
        .task_getscheduler =            selinux_task_getscheduler,
-       .task_movememory =              selinux_task_movememory,
        .task_kill =                    selinux_task_kill,
        .task_wait =                    selinux_task_wait,
        .task_prctl =                   selinux_task_prctl,
@@ -4596,9 +4327,6 @@ static struct security_operations selinux_ops = {
        .getprocattr =                  selinux_getprocattr,
        .setprocattr =                  selinux_setprocattr,
 
-       .secid_to_secctx =              selinux_secid_to_secctx,
-       .release_secctx =               selinux_release_secctx,
-
         .unix_stream_connect =         selinux_socket_unix_stream_connect,
        .unix_may_send =                selinux_socket_unix_may_send,
 
@@ -4616,8 +4344,7 @@ static struct security_operations selinux_ops = {
        .socket_setsockopt =            selinux_socket_setsockopt,
        .socket_shutdown =              selinux_socket_shutdown,
        .socket_sock_rcv_skb =          selinux_socket_sock_rcv_skb,
-       .socket_getpeersec_stream =     selinux_socket_getpeersec_stream,
-       .socket_getpeersec_dgram =      selinux_socket_getpeersec_dgram,
+       .socket_getpeersec =            selinux_socket_getpeersec,
        .sk_alloc_security =            selinux_sk_alloc_security,
        .sk_free_security =             selinux_sk_free_security,
        .sk_getsid =                    selinux_sk_getsid_security,
@@ -4626,18 +4353,10 @@ static struct security_operations selinux_ops = {
        .xfrm_policy_alloc_security =   selinux_xfrm_policy_alloc,
        .xfrm_policy_clone_security =   selinux_xfrm_policy_clone,
        .xfrm_policy_free_security =    selinux_xfrm_policy_free,
-       .xfrm_policy_delete_security =  selinux_xfrm_policy_delete,
        .xfrm_state_alloc_security =    selinux_xfrm_state_alloc,
        .xfrm_state_free_security =     selinux_xfrm_state_free,
-       .xfrm_state_delete_security =   selinux_xfrm_state_delete,
        .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,
 #endif
-
-#ifdef CONFIG_KEYS
-       .key_alloc =                    selinux_key_alloc,
-       .key_free =                     selinux_key_free,
-       .key_permission =               selinux_key_permission,
-#endif
 };
 
 static __init int selinux_init(void)
@@ -4657,9 +4376,6 @@ static __init int selinux_init(void)
        tsec = current->security;
        tsec->osid = tsec->sid = SECINITSID_KERNEL;
 
-       sel_inode_cache = kmem_cache_create("selinux_inode_security",
-                                           sizeof(struct inode_security_struct),
-                                           0, SLAB_PANIC, NULL, NULL);
        avc_init();
 
        original_ops = secondary_ops = security_ops;
@@ -4673,15 +4389,6 @@ static __init int selinux_init(void)
        } else {
                printk(KERN_INFO "SELinux:  Starting in permissive mode\n");
        }
-
-#ifdef CONFIG_KEYS
-       /* Add security information to initial keyrings */
-       selinux_key_alloc(&root_user_keyring, current,
-                         KEY_ALLOC_NOT_IN_QUOTA);
-       selinux_key_alloc(&root_session_keyring, current,
-                         KEY_ALLOC_NOT_IN_QUOTA);
-#endif
-
        return 0;
 }
 
@@ -4691,7 +4398,6 @@ void selinux_complete_init(void)
 
        /* Set up any superblocks initialized prior to the policy load. */
        printk(KERN_INFO "SELinux:  Setting up existing superblocks.\n");
-       spin_lock(&sb_lock);
        spin_lock(&sb_security_lock);
 next_sb:
        if (!list_empty(&superblock_security_head)) {
@@ -4700,20 +4406,19 @@ next_sb:
                                           struct superblock_security_struct,
                                           list);
                struct super_block *sb = sbsec->sb;
+               spin_lock(&sb_lock);
                sb->s_count++;
-               spin_unlock(&sb_security_lock);
                spin_unlock(&sb_lock);
+               spin_unlock(&sb_security_lock);
                down_read(&sb->s_umount);
                if (sb->s_root)
                        superblock_doinit(sb, NULL);
                drop_super(sb);
-               spin_lock(&sb_lock);
                spin_lock(&sb_security_lock);
                list_del_init(&sbsec->list);
                goto next_sb;
        }
        spin_unlock(&sb_security_lock);
-       spin_unlock(&sb_lock);
 }
 
 /* SELinux requires early initialization in order to label
@@ -4808,7 +4513,6 @@ int selinux_disable(void)
        printk(KERN_INFO "SELinux:  Disabled at runtime.\n");
 
        selinux_disabled = 1;
-       selinux_enabled = 0;
 
        /* Reset security_ops to the secondary module, dummy or capability. */
        security_ops = secondary_ops;