Merge branch 'audit.b3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit...
authorLinus Torvalds <torvalds@g5.osdl.org>
Sat, 25 Mar 2006 17:24:53 +0000 (09:24 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sat, 25 Mar 2006 17:24:53 +0000 (09:24 -0800)
* 'audit.b3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current: (22 commits)
  [PATCH] fix audit_init failure path
  [PATCH] EXPORT_SYMBOL patch for audit_log, audit_log_start, audit_log_end and audit_format
  [PATCH] sem2mutex: audit_netlink_sem
  [PATCH] simplify audit_free() locking
  [PATCH] Fix audit operators
  [PATCH] promiscuous mode
  [PATCH] Add tty to syscall audit records
  [PATCH] add/remove rule update
  [PATCH] audit string fields interface + consumer
  [PATCH] SE Linux audit events
  [PATCH] Minor cosmetic cleanups to the code moved into auditfilter.c
  [PATCH] Fix audit record filtering with !CONFIG_AUDITSYSCALL
  [PATCH] Fix IA64 success/failure indication in syscall auditing.
  [PATCH] Miscellaneous bug and warning fixes
  [PATCH] Capture selinux subject/object context information.
  [PATCH] Exclude messages by message type
  [PATCH] Collect more inode information during syscall processing.
  [PATCH] Pass dentry, not just name, in fsnotify creation hooks.
  [PATCH] Define new range of userspace messages.
  [PATCH] Filter rule comparators
  ...

Fixed trivial conflict in security/selinux/hooks.c

14 files changed:
1  2 
fs/namei.c
fs/open.c
include/linux/fsnotify.h
include/linux/security.h
ipc/msg.c
ipc/shm.c
kernel/Makefile
kernel/auditsc.c
net/core/dev.c
security/dummy.c
security/selinux/hooks.c
security/selinux/nlmsgtab.c
security/selinux/selinuxfs.c
security/selinux/ss/services.c

diff --combined fs/namei.c
index 712dfc77793bcb6a0bff52bc00d50248050117eb,51cfc9c3ed009c27373dcc67eaf213516f912d0b..98dc2e1343621608a391ceb019a2956221bb6d84
   */
  /*
   * [Sep 2001 AV] Single-semaphore locking scheme (kudos to David Holland)
 - * implemented.  Let's see if raised priority of ->s_vfs_rename_sem gives
 + * implemented.  Let's see if raised priority of ->s_vfs_rename_mutex gives
   * any extra contention...
   */
  
@@@ -1353,6 -1353,7 +1353,7 @@@ static int may_delete(struct inode *dir
                return -ENOENT;
  
        BUG_ON(victim->d_parent->d_inode != dir);
+       audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino);
  
        error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
        if (error)
@@@ -1422,7 -1423,7 +1423,7 @@@ struct dentry *lock_rename(struct dentr
                return NULL;
        }
  
 -      down(&p1->d_inode->i_sb->s_vfs_rename_sem);
 +      mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
  
        for (p = p1; p->d_parent != p; p = p->d_parent) {
                if (p->d_parent == p2) {
@@@ -1450,7 -1451,7 +1451,7 @@@ void unlock_rename(struct dentry *p1, s
        mutex_unlock(&p1->d_inode->i_mutex);
        if (p1 != p2) {
                mutex_unlock(&p2->d_inode->i_mutex);
 -              up(&p1->d_inode->i_sb->s_vfs_rename_sem);
 +              mutex_unlock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
        }
  }
  
@@@ -1472,7 -1473,7 +1473,7 @@@ int vfs_create(struct inode *dir, struc
        DQUOT_INIT(dir);
        error = dir->i_op->create(dir, dentry, mode, nd);
        if (!error)
-               fsnotify_create(dir, dentry->d_name.name);
+               fsnotify_create(dir, dentry);
        return error;
  }
  
@@@ -1628,12 -1629,6 +1629,12 @@@ do_last
                goto exit;
        }
  
 +      if (IS_ERR(nd->intent.open.file)) {
 +              mutex_unlock(&dir->d_inode->i_mutex);
 +              error = PTR_ERR(nd->intent.open.file);
 +              goto exit_dput;
 +      }
 +
        /* Negative dentry, just create the file */
        if (!path.dentry->d_inode) {
                if (!IS_POSIXACL(dir->d_inode))
@@@ -1799,7 -1794,7 +1800,7 @@@ int vfs_mknod(struct inode *dir, struc
        DQUOT_INIT(dir);
        error = dir->i_op->mknod(dir, dentry, mode, dev);
        if (!error)
-               fsnotify_create(dir, dentry->d_name.name);
+               fsnotify_create(dir, dentry);
        return error;
  }
  
@@@ -1876,7 -1871,7 +1877,7 @@@ int vfs_mkdir(struct inode *dir, struc
        DQUOT_INIT(dir);
        error = dir->i_op->mkdir(dir, dentry, mode);
        if (!error)
-               fsnotify_mkdir(dir, dentry->d_name.name);
+               fsnotify_mkdir(dir, dentry);
        return error;
  }
  
@@@ -2139,7 -2134,7 +2140,7 @@@ int vfs_symlink(struct inode *dir, stru
        DQUOT_INIT(dir);
        error = dir->i_op->symlink(dir, dentry, oldname);
        if (!error)
-               fsnotify_create(dir, dentry->d_name.name);
+               fsnotify_create(dir, dentry);
        return error;
  }
  
@@@ -2216,7 -2211,7 +2217,7 @@@ int vfs_link(struct dentry *old_dentry
        error = dir->i_op->link(old_dentry, dir, new_dentry);
        mutex_unlock(&old_dentry->d_inode->i_mutex);
        if (!error)
-               fsnotify_create(dir, new_dentry->d_name.name);
+               fsnotify_create(dir, new_dentry);
        return error;
  }
  
@@@ -2283,17 -2278,17 +2284,17 @@@ asmlinkage long sys_link(const char __u
   *    a) we can get into loop creation. Check is done in is_subdir().
   *    b) race potential - two innocent renames can create a loop together.
   *       That's where 4.4 screws up. Current fix: serialization on
 - *       sb->s_vfs_rename_sem. We might be more accurate, but that's another
 + *       sb->s_vfs_rename_mutex. We might be more accurate, but that's another
   *       story.
   *    c) we have to lock _three_ objects - parents and victim (if it exists).
   *       And that - after we got ->i_mutex on parents (until then we don't know
   *       whether the target exists).  Solution: try to be smart with locking
   *       order for inodes.  We rely on the fact that tree topology may change
 - *       only under ->s_vfs_rename_sem _and_ that parent of the object we
 + *       only under ->s_vfs_rename_mutex _and_ that parent of the object we
   *       move will be locked.  Thus we can rank directories by the tree
   *       (ancestors first) and rank all non-directories after them.
   *       That works since everybody except rename does "lock parent, lookup,
 - *       lock child" and rename is under ->s_vfs_rename_sem.
 + *       lock child" and rename is under ->s_vfs_rename_mutex.
   *       HOWEVER, it relies on the assumption that any object with ->lookup()
   *       has no more than 1 dentry.  If "hybrid" objects will ever appear,
   *       we'd better make sure that there's no link(2) for them.
@@@ -2627,27 -2622,16 +2628,27 @@@ int __page_symlink(struct inode *inode
        int err = -ENOMEM;
        char *kaddr;
  
 +retry:
        page = find_or_create_page(mapping, 0, gfp_mask);
        if (!page)
                goto fail;
        err = mapping->a_ops->prepare_write(NULL, page, 0, len-1);
 +      if (err == AOP_TRUNCATED_PAGE) {
 +              page_cache_release(page);
 +              goto retry;
 +      }
        if (err)
                goto fail_map;
        kaddr = kmap_atomic(page, KM_USER0);
        memcpy(kaddr, symname, len-1);
        kunmap_atomic(kaddr, KM_USER0);
 -      mapping->a_ops->commit_write(NULL, page, 0, len-1);
 +      err = mapping->a_ops->commit_write(NULL, page, 0, len-1);
 +      if (err == AOP_TRUNCATED_PAGE) {
 +              page_cache_release(page);
 +              goto retry;
 +      }
 +      if (err)
 +              goto fail_map;
        /*
         * Notice that we are _not_ going to block here - end of page is
         * unmapped, so this will only try to map the rest of page, see
         */
        if (!PageUptodate(page)) {
                err = mapping->a_ops->readpage(NULL, page);
 -              wait_on_page_locked(page);
 +              if (err != AOP_TRUNCATED_PAGE)
 +                      wait_on_page_locked(page);
        } else {
                unlock_page(page);
        }
diff --combined fs/open.c
index 7d02d19bd0a28281a108353883902fae745e1f10,70510004d06eb5620f0a66253c1ce071e0726a18..c32c89d6d8dbed71f831e94f8aa0c67eade8cfc1
+++ b/fs/open.c
@@@ -27,6 -27,7 +27,7 @@@
  #include <linux/pagemap.h>
  #include <linux/syscalls.h>
  #include <linux/rcupdate.h>
+ #include <linux/audit.h>
  
  #include <asm/unistd.h>
  
@@@ -626,6 -627,8 +627,8 @@@ asmlinkage long sys_fchmod(unsigned in
        dentry = file->f_dentry;
        inode = dentry->d_inode;
  
+       audit_inode(NULL, inode, 0);
        err = -EROFS;
        if (IS_RDONLY(inode))
                goto out_putf;
@@@ -775,7 -778,10 +778,10 @@@ asmlinkage long sys_fchown(unsigned in
  
        file = fget(fd);
        if (file) {
-               error = chown_common(file->f_dentry, user, group);
+               struct dentry * dentry;
+               dentry = file->f_dentry;
+               audit_inode(NULL, dentry->d_inode, 0);
+               error = chown_common(dentry, user, group);
                fput(file);
        }
        return error;
@@@ -890,10 -896,6 +896,10 @@@ EXPORT_SYMBOL(filp_open)
   * a fully instantiated struct file to the caller.
   * This function is meant to be called from within a filesystem's
   * lookup method.
 + * Beware of calling it for non-regular files! Those ->open methods might block
 + * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
 + * leading to a deadlock, as nobody can open that fifo anymore, because
 + * another process to open fifo will block on locked parent when doing lookup).
   * Note that in case of error, nd->intent.open.file is destroyed, but the
   * path information remains valid.
   * If the open callback is set to NULL, then the standard f_op->open()
@@@ -977,7 -979,7 +983,7 @@@ repeat
        fdt = files_fdtable(files);
        fd = find_next_zero_bit(fdt->open_fds->fds_bits,
                                fdt->max_fdset,
 -                              fdt->next_fd);
 +                              files->next_fd);
  
        /*
         * N.B. For clone tasks sharing a files structure, this test
  
        FD_SET(fd, fdt->open_fds);
        FD_CLR(fd, fdt->close_on_exec);
 -      fdt->next_fd = fd + 1;
 +      files->next_fd = fd + 1;
  #if 1
        /* Sanity check */
        if (fdt->fd[fd] != NULL) {
@@@ -1023,8 -1025,8 +1029,8 @@@ static void __put_unused_fd(struct file
  {
        struct fdtable *fdt = files_fdtable(files);
        __FD_CLR(fd, fdt->open_fds);
 -      if (fd < fdt->next_fd)
 -              fdt->next_fd = fd;
 +      if (fd < files->next_fd)
 +              files->next_fd = fd;
  }
  
  void fastcall put_unused_fd(unsigned int fd)
diff --combined include/linux/fsnotify.h
index f7e517c1f1bdb493d9e02c729afc6f6755d24252,94919c376a723ad50804af9a85921b309b5eb171..11438eff4d4455573f76789edfd5ffb0cc646473
  
  #include <linux/dnotify.h>
  #include <linux/inotify.h>
+ #include <linux/audit.h>
  
 +/*
 + * fsnotify_d_instantiate - instantiate a dentry for inode
 + * Called with dcache_lock held.
 + */
 +static inline void fsnotify_d_instantiate(struct dentry *entry,
 +                                              struct inode *inode)
 +{
 +      inotify_d_instantiate(entry, inode);
 +}
 +
 +/*
 + * fsnotify_d_move - entry has been moved
 + * Called with dcache_lock and entry->d_lock held.
 + */
 +static inline void fsnotify_d_move(struct dentry *entry)
 +{
 +      inotify_d_move(entry);
 +}
 +
  /*
   * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
   */
@@@ -64,6 -46,8 +65,8 @@@ static inline void fsnotify_move(struc
        if (source) {
                inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL);
        }
+       audit_inode_child(old_name, source, old_dir->i_ino);
+       audit_inode_child(new_name, target, new_dir->i_ino);
  }
  
  /*
@@@ -89,19 -73,22 +92,22 @@@ static inline void fsnotify_inoderemove
  /*
   * fsnotify_create - 'name' was linked in
   */
- static inline void fsnotify_create(struct inode *inode, const char *name)
+ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
  {
        inode_dir_notify(inode, DN_CREATE);
-       inotify_inode_queue_event(inode, IN_CREATE, 0, name);
+       inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name);
+       audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
  }
  
  /*
   * fsnotify_mkdir - directory 'name' was created
   */
- static inline void fsnotify_mkdir(struct inode *inode, const char *name)
+ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
  {
        inode_dir_notify(inode, DN_CREATE);
-       inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, name);
+       inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, 
+                                 dentry->d_name.name);
+       audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
  }
  
  /*
diff --combined include/linux/security.h
index 3c19be35124b03b2526fb803ef93a45b92c26896,2a502250eb5cd176ddf18cac5913ee5ef1ce73fe..aaa0a5cdbf751c857f5a5adcfbe880da478c1acf
@@@ -869,6 -869,11 +869,11 @@@ struct swap_info_struct
   *    @ipcp contains the kernel IPC permission structure
   *    @flag contains the desired (requested) permission set
   *    Return 0 if permission is granted.
+  * @ipc_getsecurity:
+  *      Copy the security label associated with the ipc object into
+  *      @buffer.  @buffer may be NULL to request the size of the buffer 
+  *      required.  @size indicates the size of @buffer in bytes. Return 
+  *      number of bytes used/required on success.
   *
   * Security hooks for individual messages held in System V IPC message queues
   * @msg_msg_alloc_security:
   *    @effective contains the effective capability set.
   *    @inheritable contains the inheritable capability set.
   *    @permitted contains the permitted capability set.
 + * @capable:
 + *    Check whether the @tsk process has the @cap capability.
 + *    @tsk contains the task_struct for the process.
 + *    @cap contains the capability <include/linux/capability.h>.
 + *    Return 0 if the capability is granted for @tsk.
   * @acct:
   *    Check permission before enabling or disabling process accounting.  If
   *    accounting is being enabled, then @file refers to the open file used to
   *    @table contains the ctl_table structure for the sysctl variable.
   *    @op contains the operation (001 = search, 002 = write, 004 = read).
   *    Return 0 if permission is granted.
 - * @capable:
 - *    Check whether the @tsk process has the @cap capability.
 - *    @tsk contains the task_struct for the process.
 - *    @cap contains the capability <include/linux/capability.h>.
 - *    Return 0 if the capability is granted for @tsk.
   * @syslog:
   *    Check permission before accessing the kernel message ring or changing
   *    logging to the console.
@@@ -1099,9 -1104,9 +1104,9 @@@ struct security_operations 
                            kernel_cap_t * effective,
                            kernel_cap_t * inheritable,
                            kernel_cap_t * permitted);
 +      int (*capable) (struct task_struct * tsk, int cap);
        int (*acct) (struct file * file);
        int (*sysctl) (struct ctl_table * table, int op);
 -      int (*capable) (struct task_struct * tsk, int cap);
        int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
        int (*quota_on) (struct dentry * dentry);
        int (*syslog) (int type);
        int (*inode_getxattr) (struct dentry *dentry, char *name);
        int (*inode_listxattr) (struct dentry *dentry);
        int (*inode_removexattr) (struct dentry *dentry, char *name);
-       int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size, int err);
+       const char *(*inode_xattr_getsuffix) (void);
+       int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
        int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
        int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
  
        void (*task_to_inode)(struct task_struct *p, struct inode *inode);
  
        int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+       int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size);
  
        int (*msg_msg_alloc_security) (struct msg_msg * msg);
        void (*msg_msg_free_security) (struct msg_msg * msg);
        int (*socket_setsockopt) (struct socket * sock, int level, int optname);
        int (*socket_shutdown) (struct socket * sock, int how);
        int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
 -      int (*socket_getpeersec) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
 +      int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
 +      int (*socket_getpeersec_dgram) (struct sk_buff *skb, char **secdata, u32 *seclen);
        int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
        void (*sk_free_security) (struct sock *sk);
        unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir);
@@@ -1347,11 -1353,6 +1354,11 @@@ static inline void security_capset_set 
        security_ops->capset_set (target, effective, inheritable, permitted);
  }
  
 +static inline int security_capable(struct task_struct *tsk, int cap)
 +{
 +      return security_ops->capable(tsk, cap);
 +}
 +
  static inline int security_acct (struct file *file)
  {
        return security_ops->acct (file);
@@@ -1680,7 -1681,12 +1687,12 @@@ static inline int security_inode_remove
        return security_ops->inode_removexattr (dentry, name);
  }
  
- static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+ static inline const char *security_inode_xattr_getsuffix(void)
+ {
+       return security_ops->inode_xattr_getsuffix();
+ }
+ static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
  {
        if (unlikely (IS_PRIVATE (inode)))
                return 0;
@@@ -1875,6 -1881,11 +1887,11 @@@ static inline int security_ipc_permissi
        return security_ops->ipc_permission (ipcp, flag);
  }
  
+ static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+ {
+       return security_ops->ipc_getsecurity(ipcp, buffer, size);
+ }
  static inline int security_msg_msg_alloc (struct msg_msg * msg)
  {
        return security_ops->msg_msg_alloc_security (msg);
@@@ -2055,11 -2066,6 +2072,11 @@@ static inline void security_capset_set 
        cap_capset_set (target, effective, inheritable, permitted);
  }
  
 +static inline int security_capable(struct task_struct *tsk, int cap)
 +{
 +      return cap_capable(tsk, cap);
 +}
 +
  static inline int security_acct (struct file *file)
  {
        return 0;
@@@ -2327,7 -2333,12 +2344,12 @@@ static inline int security_inode_remove
        return cap_inode_removexattr(dentry, name);
  }
  
- static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+ static inline const char *security_inode_xattr_getsuffix (void)
+ {
+       return NULL ;
+ }
+ static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
  {
        return -EOPNOTSUPP;
  }
@@@ -2510,6 -2521,11 +2532,11 @@@ static inline int security_ipc_permissi
        return 0;
  }
  
+ static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+ {
+       return -EOPNOTSUPP;
+ }
  static inline int security_msg_msg_alloc (struct msg_msg * msg)
  {
        return 0;
@@@ -2752,16 -2768,10 +2779,16 @@@ static inline int security_sock_rcv_sk
        return security_ops->socket_sock_rcv_skb (sk, skb);
  }
  
 -static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
 -                                           int __user *optlen, unsigned len)
 +static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 +                                                  int __user *optlen, unsigned len)
 +{
 +      return security_ops->socket_getpeersec_stream(sock, optval, optlen, len);
 +}
 +
 +static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
 +                                                 u32 *seclen)
  {
 -      return security_ops->socket_getpeersec(sock, optval, optlen, len);
 +      return security_ops->socket_getpeersec_dgram(skb, secdata, seclen);
  }
  
  static inline int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
@@@ -2880,14 -2890,8 +2907,14 @@@ static inline int security_sock_rcv_sk
        return 0;
  }
  
 -static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
 -                                           int __user *optlen, unsigned len)
 +static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 +                                                  int __user *optlen, unsigned len)
 +{
 +      return -ENOPROTOOPT;
 +}
 +
 +static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
 +                                                 u32 *seclen)
  {
        return -ENOPROTOOPT;
  }
diff --combined ipc/msg.c
index 60c1e5c23418116326fdd36bd05c5b65cd93643c,8c30ec2f6e34aaab47f08dc90b7a560725043fff..7eec5ed32379dc7173432d05c85ca23ccf89c80d
+++ b/ipc/msg.c
@@@ -220,7 -220,8 +220,7 @@@ asmlinkage long sys_msgget (key_t key, 
                ret = -EEXIST;
        } else {
                msq = msg_lock(id);
 -              if(msq==NULL)
 -                      BUG();
 +              BUG_ON(msq==NULL);
                if (ipcperms(&msq->q_perm, msgflg))
                        ret = -EACCES;
                else {
@@@ -428,8 -429,6 +428,6 @@@ asmlinkage long sys_msgctl (int msqid, 
                        return -EFAULT;
                if (copy_msqid_from_user (&setbuf, buf, version))
                        return -EFAULT;
-               if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
-                       return err;
                break;
        case IPC_RMID:
                break;
        switch (cmd) {
        case IPC_SET:
        {
+               if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+                       goto out_unlock_up;
                err = -EPERM;
                if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
                        goto out_unlock_up;
diff --combined ipc/shm.c
index 16fe2786087d003881b76df50a192cafbe8e2b1a,a88c8a02e7f3479378238f51e779e93c19774b3a..6f9615c09fb2fe903cca007f79ac6a986ff349bc
+++ b/ipc/shm.c
@@@ -620,13 -620,13 +620,13 @@@ asmlinkage long sys_shmctl (int shmid, 
                        err = -EFAULT;
                        goto out;
                }
-               if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
-                       return err;
                down(&shm_ids.sem);
                shp = shm_lock(shmid);
                err=-EINVAL;
                if(shp==NULL)
                        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);
                if(err)
                        goto out_unlock_up;
@@@ -814,9 -814,6 +814,9 @@@ asmlinkage long sys_shmdt(char __user *
        loff_t size = 0;
        int retval = -EINVAL;
  
 +      if (addr & ~PAGE_MASK)
 +              return retval;
 +
        down_write(&mm->mmap_sem);
  
        /*
diff --combined kernel/Makefile
index aebd7a78984e8aa2e82b95579d33f8c754d9586d,58cf129e56225b655e92b8944b24990320ee7bca..ff1c11dc12cf64234e701ee82a8f5a7d1b66a29a
@@@ -26,7 -26,7 +26,7 @@@ obj-$(CONFIG_COMPAT) += compat.
  obj-$(CONFIG_CPUSETS) += cpuset.o
  obj-$(CONFIG_IKCONFIG) += configs.o
  obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
- obj-$(CONFIG_AUDIT) += audit.o
+ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
  obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
  obj-$(CONFIG_KPROBES) += kprobes.o
  obj-$(CONFIG_SYSFS) += ksysfs.o
@@@ -34,7 -34,6 +34,7 @@@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += soft
  obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
  obj-$(CONFIG_SECCOMP) += seccomp.o
  obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 +obj-$(CONFIG_RELAY) += relay.o
  
  ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
  # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --combined kernel/auditsc.c
index c4394abcd5e6952a293d30626a6f17c13b832822,b613ec89e99c1a52aeefe7afbac95f0da3c00ae9..7f160df21a23e22a3d8e0e36b29712bcc9758692
@@@ -2,6 -2,8 +2,8 @@@
   * Handles all system-call specific auditing features.
   *
   * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+  * Copyright 2005 Hewlett-Packard Development Company, L.P.
+  * Copyright (C) 2005 IBM Corporation
   * All Rights Reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * this file -- see entry.S) is based on a GPL'd patch written by
   * okir@suse.de and Copyright 2003 SuSE Linux AG.
   *
+  * The support of additional filter rules compares (>, <, >=, <=) was
+  * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005.
+  *
+  * Modified by Amy Griffis <amy.griffis@hp.com> to collect additional
+  * filesystem information.
+  *
+  * Subject and object context labeling support added by <danjones@us.ibm.com>
+  * and <dustin.kirkland@us.ibm.com> for LSPP certification compliance.
   */
  
  #include <linux/init.h>
  #include <asm/types.h>
  #include <asm/atomic.h>
+ #include <asm/types.h>
+ #include <linux/fs.h>
+ #include <linux/namei.h>
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/mount.h>
  #include <linux/audit.h>
  #include <linux/personality.h>
  #include <linux/time.h>
- #include <linux/kthread.h>
  #include <linux/netlink.h>
  #include <linux/compiler.h>
  #include <asm/unistd.h>
+ #include <linux/security.h>
+ #include <linux/list.h>
+ #include <linux/tty.h>
+ #include "audit.h"
  
- /* 0 = no checking
-    1 = put_count checking
-    2 = verbose put_count checking
- */
- #define AUDIT_DEBUG 0
+ extern struct list_head audit_filter_list[];
  
  /* No syscall auditing will take place unless audit_enabled != 0. */
  extern int audit_enabled;
   * path_lookup. */
  #define AUDIT_NAMES_RESERVED 7
  
- /* At task start time, the audit_state is set in the audit_context using
-    a per-task filter.  At syscall entry, the audit_state is augmented by
-    the syscall filter. */
- enum audit_state {
-       AUDIT_DISABLED,         /* Do not create per-task audit_context.
-                                * No syscall-specific audit records can
-                                * be generated. */
-       AUDIT_SETUP_CONTEXT,    /* Create the per-task audit_context,
-                                * but don't necessarily fill it in at
-                                * syscall entry time (i.e., filter
-                                * instead). */
-       AUDIT_BUILD_CONTEXT,    /* Create the per-task audit_context,
-                                * and always fill it in at syscall
-                                * entry time.  This makes a full
-                                * syscall record available if some
-                                * other part of the kernel decides it
-                                * should be recorded. */
-       AUDIT_RECORD_CONTEXT    /* Create the per-task audit_context,
-                                * always fill it in at syscall entry
-                                * time, and always write out the audit
-                                * record at syscall exit time.  */
- };
  /* When fs/namei.c:getname() is called, we store the pointer in name and
   * we don't let putname() free it (instead we free all of the saved
   * pointers at syscall exit time).
  struct audit_names {
        const char      *name;
        unsigned long   ino;
+       unsigned long   pino;
        dev_t           dev;
        umode_t         mode;
        uid_t           uid;
        gid_t           gid;
        dev_t           rdev;
-       unsigned        flags;
+       char            *ctx;
  };
  
  struct audit_aux_data {
@@@ -115,6 -106,7 +106,7 @@@ struct audit_aux_data_ipcctl 
        uid_t                   uid;
        gid_t                   gid;
        mode_t                  mode;
+       char                    *ctx;
  };
  
  struct audit_aux_data_socketcall {
@@@ -167,290 -159,72 +159,72 @@@ struct audit_context 
  #endif
  };
  
-                               /* Public API */
- /* There are three lists of rules -- one to search at task creation
-  * time, one to search at syscall entry time, and another to search at
-  * syscall exit time. */
- static struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
-       LIST_HEAD_INIT(audit_filter_list[0]),
-       LIST_HEAD_INIT(audit_filter_list[1]),
-       LIST_HEAD_INIT(audit_filter_list[2]),
-       LIST_HEAD_INIT(audit_filter_list[3]),
-       LIST_HEAD_INIT(audit_filter_list[4]),
- #if AUDIT_NR_FILTERS != 5
- #error Fix audit_filter_list initialiser
- #endif
- };
- struct audit_entry {
-       struct list_head  list;
-       struct rcu_head   rcu;
-       struct audit_rule rule;
- };
- extern int audit_pid;
- /* Copy rule from user-space to kernel-space.  Called from 
-  * audit_add_rule during AUDIT_ADD. */
- static inline int audit_copy_rule(struct audit_rule *d, struct audit_rule *s)
- {
-       int i;
-       if (s->action != AUDIT_NEVER
-           && s->action != AUDIT_POSSIBLE
-           && s->action != AUDIT_ALWAYS)
-               return -1;
-       if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS)
-               return -1;
-       if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS)
-               return -1;
-       d->flags        = s->flags;
-       d->action       = s->action;
-       d->field_count  = s->field_count;
-       for (i = 0; i < d->field_count; i++) {
-               d->fields[i] = s->fields[i];
-               d->values[i] = s->values[i];
-       }
-       for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i];
-       return 0;
- }
- /* Check to see if two rules are identical.  It is called from
-  * audit_add_rule during AUDIT_ADD and 
-  * audit_del_rule during AUDIT_DEL. */
- static inline int audit_compare_rule(struct audit_rule *a, struct audit_rule *b)
- {
-       int i;
-       if (a->flags != b->flags)
-               return 1;
-       if (a->action != b->action)
-               return 1;
-       if (a->field_count != b->field_count)
-               return 1;
-       for (i = 0; i < a->field_count; i++) {
-               if (a->fields[i] != b->fields[i]
-                   || a->values[i] != b->values[i])
-                       return 1;
-       }
-       for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
-               if (a->mask[i] != b->mask[i])
-                       return 1;
-       return 0;
- }
- /* Note that audit_add_rule and audit_del_rule are called via
-  * audit_receive() in audit.c, and are protected by
-  * audit_netlink_sem. */
- static inline int audit_add_rule(struct audit_rule *rule,
-                                 struct list_head *list)
- {
-       struct audit_entry  *entry;
-       /* Do not use the _rcu iterator here, since this is the only
-        * addition routine. */
-       list_for_each_entry(entry, list, list) {
-               if (!audit_compare_rule(rule, &entry->rule)) {
-                       return -EEXIST;
-               }
-       }
-       if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
-               return -ENOMEM;
-       if (audit_copy_rule(&entry->rule, rule)) {
-               kfree(entry);
-               return -EINVAL;
-       }
-       if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
-               entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
-               list_add_rcu(&entry->list, list);
-       } else {
-               list_add_tail_rcu(&entry->list, list);
-       }
-       return 0;
- }
- static inline void audit_free_rule(struct rcu_head *head)
- {
-       struct audit_entry *e = container_of(head, struct audit_entry, rcu);
-       kfree(e);
- }
- /* Note that audit_add_rule and audit_del_rule are called via
-  * audit_receive() in audit.c, and are protected by
-  * audit_netlink_sem. */
- static inline int audit_del_rule(struct audit_rule *rule,
-                                struct list_head *list)
- {
-       struct audit_entry  *e;
-       /* Do not use the _rcu iterator here, since this is the only
-        * deletion routine. */
-       list_for_each_entry(e, list, list) {
-               if (!audit_compare_rule(rule, &e->rule)) {
-                       list_del_rcu(&e->list);
-                       call_rcu(&e->rcu, audit_free_rule);
-                       return 0;
-               }
-       }
-       return -ENOENT;         /* No matching rule */
- }
- static int audit_list_rules(void *_dest)
- {
-       int pid, seq;
-       int *dest = _dest;
-       struct audit_entry *entry;
-       int i;
-       pid = dest[0];
-       seq = dest[1];
-       kfree(dest);
-       down(&audit_netlink_sem);
-       /* The *_rcu iterators not needed here because we are
-          always called with audit_netlink_sem held. */
-       for (i=0; i<AUDIT_NR_FILTERS; i++) {
-               list_for_each_entry(entry, &audit_filter_list[i], list)
-                       audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
-                                        &entry->rule, sizeof(entry->rule));
-       }
-       audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
-       
-       up(&audit_netlink_sem);
-       return 0;
- }
- int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
-                                                       uid_t loginuid)
- {
-       struct task_struct *tsk;
-       int *dest;
-       int                err = 0;
-       unsigned listnr;
-       switch (type) {
-       case AUDIT_LIST:
-               /* We can't just spew out the rules here because we might fill
-                * the available socket buffer space and deadlock waiting for
-                * auditctl to read from it... which isn't ever going to
-                * happen if we're actually running in the context of auditctl
-                * trying to _send_ the stuff */
-                
-               dest = kmalloc(2 * sizeof(int), GFP_KERNEL);
-               if (!dest)
-                       return -ENOMEM;
-               dest[0] = pid;
-               dest[1] = seq;
-               tsk = kthread_run(audit_list_rules, dest, "audit_list_rules");
-               if (IS_ERR(tsk)) {
-                       kfree(dest);
-                       err = PTR_ERR(tsk);
-               }
-               break;
-       case AUDIT_ADD:
-               listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND;
-               if (listnr >= AUDIT_NR_FILTERS)
-                       return -EINVAL;
-               err = audit_add_rule(data, &audit_filter_list[listnr]);
-               if (!err)
-                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                                 "auid=%u added an audit rule\n", loginuid);
-               break;
-       case AUDIT_DEL:
-               listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND;
-               if (listnr >= AUDIT_NR_FILTERS)
-                       return -EINVAL;
-               err = audit_del_rule(data, &audit_filter_list[listnr]);
-               if (!err)
-                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                                 "auid=%u removed an audit rule\n", loginuid);
-               break;
-       default:
-               return -EINVAL;
-       }
-       return err;
- }
  
  /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
   * otherwise. */
  static int audit_filter_rules(struct task_struct *tsk,
-                             struct audit_rule *rule,
+                             struct audit_krule *rule,
                              struct audit_context *ctx,
                              enum audit_state *state)
  {
        int i, j;
  
        for (i = 0; i < rule->field_count; i++) {
-               u32 field  = rule->fields[i] & ~AUDIT_NEGATE;
-               u32 value  = rule->values[i];
+               struct audit_field *f = &rule->fields[i];
                int result = 0;
  
-               switch (field) {
+               switch (f->type) {
                case AUDIT_PID:
-                       result = (tsk->pid == value);
+                       result = audit_comparator(tsk->pid, f->op, f->val);
                        break;
                case AUDIT_UID:
-                       result = (tsk->uid == value);
+                       result = audit_comparator(tsk->uid, f->op, f->val);
                        break;
                case AUDIT_EUID:
-                       result = (tsk->euid == value);
+                       result = audit_comparator(tsk->euid, f->op, f->val);
                        break;
                case AUDIT_SUID:
-                       result = (tsk->suid == value);
+                       result = audit_comparator(tsk->suid, f->op, f->val);
                        break;
                case AUDIT_FSUID:
-                       result = (tsk->fsuid == value);
+                       result = audit_comparator(tsk->fsuid, f->op, f->val);
                        break;
                case AUDIT_GID:
-                       result = (tsk->gid == value);
+                       result = audit_comparator(tsk->gid, f->op, f->val);
                        break;
                case AUDIT_EGID:
-                       result = (tsk->egid == value);
+                       result = audit_comparator(tsk->egid, f->op, f->val);
                        break;
                case AUDIT_SGID:
-                       result = (tsk->sgid == value);
+                       result = audit_comparator(tsk->sgid, f->op, f->val);
                        break;
                case AUDIT_FSGID:
-                       result = (tsk->fsgid == value);
+                       result = audit_comparator(tsk->fsgid, f->op, f->val);
                        break;
                case AUDIT_PERS:
-                       result = (tsk->personality == value);
+                       result = audit_comparator(tsk->personality, f->op, f->val);
                        break;
                case AUDIT_ARCH:
-                       if (ctx) 
-                               result = (ctx->arch == value);
+                       if (ctx)
+                               result = audit_comparator(ctx->arch, f->op, f->val);
                        break;
  
                case AUDIT_EXIT:
                        if (ctx && ctx->return_valid)
-                               result = (ctx->return_code == value);
+                               result = audit_comparator(ctx->return_code, f->op, f->val);
                        break;
                case AUDIT_SUCCESS:
                        if (ctx && ctx->return_valid) {
-                               if (value)
-                                       result = (ctx->return_valid == AUDITSC_SUCCESS);
+                               if (f->val)
+                                       result = audit_comparator(ctx->return_valid, f->op, AUDITSC_SUCCESS);
                                else
-                                       result = (ctx->return_valid == AUDITSC_FAILURE);
+                                       result = audit_comparator(ctx->return_valid, f->op, AUDITSC_FAILURE);
                        }
                        break;
                case AUDIT_DEVMAJOR:
                        if (ctx) {
                                for (j = 0; j < ctx->name_count; j++) {
-                                       if (MAJOR(ctx->names[j].dev)==value) {
+                                       if (audit_comparator(MAJOR(ctx->names[j].dev),  f->op, f->val)) {
                                                ++result;
                                                break;
                                        }
                case AUDIT_DEVMINOR:
                        if (ctx) {
                                for (j = 0; j < ctx->name_count; j++) {
-                                       if (MINOR(ctx->names[j].dev)==value) {
+                                       if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) {
                                                ++result;
                                                break;
                                        }
                case AUDIT_INODE:
                        if (ctx) {
                                for (j = 0; j < ctx->name_count; j++) {
-                                       if (ctx->names[j].ino == value) {
+                                       if (audit_comparator(ctx->names[j].ino, f->op, f->val) ||
+                                           audit_comparator(ctx->names[j].pino, f->op, f->val)) {
                                                ++result;
                                                break;
                                        }
                case AUDIT_LOGINUID:
                        result = 0;
                        if (ctx)
-                               result = (ctx->loginuid == value);
+                               result = audit_comparator(ctx->loginuid, f->op, f->val);
                        break;
                case AUDIT_ARG0:
                case AUDIT_ARG1:
                case AUDIT_ARG2:
                case AUDIT_ARG3:
                        if (ctx)
-                               result = (ctx->argv[field-AUDIT_ARG0]==value);
+                               result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
                        break;
                }
  
-               if (rule->fields[i] & AUDIT_NEGATE)
-                       result = !result;
                if (!result)
                        return 0;
        }
@@@ -527,7 -300,7 +300,7 @@@ static enum audit_state audit_filter_ta
  /* At syscall entry and exit time, this filter is called if the
   * audit_state is not low enough that auditing cannot take place, but is
   * also not high enough that we already know we have to write an audit
-  * record (i.e., the state is AUDIT_SETUP_CONTEXT or  AUDIT_BUILD_CONTEXT).
+  * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT).
   */
  static enum audit_state audit_filter_syscall(struct task_struct *tsk,
                                             struct audit_context *ctx,
  
        rcu_read_lock();
        if (!list_empty(list)) {
-                   int word = AUDIT_WORD(ctx->major);
-                   int bit  = AUDIT_BIT(ctx->major);
-                   list_for_each_entry_rcu(e, list, list) {
-                           if ((e->rule.mask[word] & bit) == bit
-                               && audit_filter_rules(tsk, &e->rule, ctx, &state)) {
-                                   rcu_read_unlock();
-                                   return state;
-                           }
-                   }
-       }
-       rcu_read_unlock();
-       return AUDIT_BUILD_CONTEXT;
- }
- static int audit_filter_user_rules(struct netlink_skb_parms *cb,
-                             struct audit_rule *rule,
-                             enum audit_state *state)
- {
-       int i;
-       for (i = 0; i < rule->field_count; i++) {
-               u32 field  = rule->fields[i] & ~AUDIT_NEGATE;
-               u32 value  = rule->values[i];
-               int result = 0;
-               switch (field) {
-               case AUDIT_PID:
-                       result = (cb->creds.pid == value);
-                       break;
-               case AUDIT_UID:
-                       result = (cb->creds.uid == value);
-                       break;
-               case AUDIT_GID:
-                       result = (cb->creds.gid == value);
-                       break;
-               case AUDIT_LOGINUID:
-                       result = (cb->loginuid == value);
-                       break;
-               }
-               if (rule->fields[i] & AUDIT_NEGATE)
-                       result = !result;
-               if (!result)
-                       return 0;
-       }
-       switch (rule->action) {
-       case AUDIT_NEVER:    *state = AUDIT_DISABLED;       break;
-       case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT;  break;
-       case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;
-       }
-       return 1;
- }
- int audit_filter_user(struct netlink_skb_parms *cb, int type)
- {
-       struct audit_entry *e;
-       enum audit_state   state;
-       int ret = 1;
-       rcu_read_lock();
-       list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
-               if (audit_filter_user_rules(cb, &e->rule, &state)) {
-                       if (state == AUDIT_DISABLED)
-                               ret = 0;
-                       break;
+               int word = AUDIT_WORD(ctx->major);
+               int bit  = AUDIT_BIT(ctx->major);
+               list_for_each_entry_rcu(e, list, list) {
+                       if ((e->rule.mask[word] & bit) == bit
+                                       && audit_filter_rules(tsk, &e->rule, ctx, &state)) {
+                               rcu_read_unlock();
+                               return state;
+                       }
                }
        }
        rcu_read_unlock();
-       return ret; /* Audit by default */
+       return AUDIT_BUILD_CONTEXT;
  }
  
  /* This should be called with task_lock() held. */
@@@ -654,17 -369,18 +369,18 @@@ static inline void audit_free_names(str
  #if AUDIT_DEBUG == 2
        if (context->auditable
            ||context->put_count + context->ino_count != context->name_count) {
-               printk(KERN_ERR "audit.c:%d(:%d): major=%d in_syscall=%d"
+               printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
                       " name_count=%d put_count=%d"
                       " ino_count=%d [NOT freeing]\n",
-                      __LINE__,
+                      __FILE__, __LINE__,
                       context->serial, context->major, context->in_syscall,
                       context->name_count, context->put_count,
                       context->ino_count);
-               for (i = 0; i < context->name_count; i++)
+               for (i = 0; i < context->name_count; i++) {
                        printk(KERN_ERR "names[%d] = %p = %s\n", i,
                               context->names[i].name,
-                              context->names[i].name);
+                              context->names[i].name ?: "(null)");
+               }
                dump_stack();
                return;
        }
        context->ino_count  = 0;
  #endif
  
-       for (i = 0; i < context->name_count; i++)
+       for (i = 0; i < context->name_count; i++) {
+               char *p = context->names[i].ctx;
+               context->names[i].ctx = NULL;
+               kfree(p);
                if (context->names[i].name)
                        __putname(context->names[i].name);
+       }
        context->name_count = 0;
        if (context->pwd)
                dput(context->pwd);
@@@ -696,6 -416,12 +416,12 @@@ static inline void audit_free_aux(struc
                        dput(axi->dentry);
                        mntput(axi->mnt);
                }
+               if ( aux->type == AUDIT_IPC ) {
+                       struct audit_aux_data_ipcctl *axi = (void *)aux;
+                       if (axi->ctx)
+                               kfree(axi->ctx);
+               }
                context->aux = aux->next;
                kfree(aux);
        }
@@@ -721,10 -447,15 +447,15 @@@ static inline struct audit_context *aud
        return context;
  }
  
- /* Filter on the task information and allocate a per-task audit context
+ /**
+  * audit_alloc - allocate an audit context block for a task
+  * @tsk: task
+  *
+  * Filter on the task information and allocate a per-task audit context
   * if necessary.  Doing so turns on system call auditing for the
   * specified task.  This is called from copy_process, so no lock is
-  * needed. */
+  * needed.
+  */
  int audit_alloc(struct task_struct *tsk)
  {
        struct audit_context *context;
@@@ -775,7 -506,37 +506,37 @@@ static inline void audit_free_context(s
                printk(KERN_ERR "audit: freed %d contexts\n", count);
  }
  
- static void audit_log_task_info(struct audit_buffer *ab)
+ static void audit_log_task_context(struct audit_buffer *ab, gfp_t gfp_mask)
+ {
+       char *ctx = NULL;
+       ssize_t len = 0;
+       len = security_getprocattr(current, "current", NULL, 0);
+       if (len < 0) {
+               if (len != -EINVAL)
+                       goto error_path;
+               return;
+       }
+       ctx = kmalloc(len, gfp_mask);
+       if (!ctx)
+               goto error_path;
+       len = security_getprocattr(current, "current", ctx, len);
+       if (len < 0 )
+               goto error_path;
+       audit_log_format(ab, " subj=%s", ctx);
+       return;
+ error_path:
+       if (ctx)
+               kfree(ctx);
+       audit_panic("error in audit_log_task_context");
+       return;
+ }
+ static void audit_log_task_info(struct audit_buffer *ab, gfp_t gfp_mask)
  {
        char name[sizeof(current->comm)];
        struct mm_struct *mm = current->mm;
        if (!mm)
                return;
  
+       /*
+        * this is brittle; all callers that pass GFP_ATOMIC will have
+        * NULL current->mm and we won't get here.
+        */
        down_read(&mm->mmap_sem);
        vma = mm->mmap;
        while (vma) {
                vma = vma->vm_next;
        }
        up_read(&mm->mmap_sem);
+       audit_log_task_context(ab, gfp_mask);
  }
  
  static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
        int i;
        struct audit_buffer *ab;
        struct audit_aux_data *aux;
+       const char *tty;
  
        ab = audit_log_start(context, gfp_mask, AUDIT_SYSCALL);
        if (!ab)
                audit_log_format(ab, " success=%s exit=%ld", 
                                 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
                                 context->return_code);
+       if (current->signal->tty && current->signal->tty->name)
+               tty = current->signal->tty->name;
+       else
+               tty = "(none)";
        audit_log_format(ab,
                  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
                  " pid=%d auid=%u uid=%u gid=%u"
                  " euid=%u suid=%u fsuid=%u"
-                 " egid=%u sgid=%u fsgid=%u",
+                 " egid=%u sgid=%u fsgid=%u tty=%s",
                  context->argv[0],
                  context->argv[1],
                  context->argv[2],
                  context->uid,
                  context->gid,
                  context->euid, context->suid, context->fsuid,
-                 context->egid, context->sgid, context->fsgid);
-       audit_log_task_info(ab);
+                 context->egid, context->sgid, context->fsgid, tty);
+       audit_log_task_info(ab, gfp_mask);
        audit_log_end(ab);
  
        for (aux = context->aux; aux; aux = aux->next) {
                case AUDIT_IPC: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab, 
-                                        " qbytes=%lx iuid=%u igid=%u mode=%x",
-                                        axi->qbytes, axi->uid, axi->gid, axi->mode);
+                                        " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+                                        axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
                        break; }
  
                case AUDIT_SOCKETCALL: {
                }
        }
        for (i = 0; i < context->name_count; i++) {
+               unsigned long ino  = context->names[i].ino;
+               unsigned long pino = context->names[i].pino;
                ab = audit_log_start(context, gfp_mask, AUDIT_PATH);
                if (!ab)
                        continue; /* audit_panic has been called */
  
                audit_log_format(ab, "item=%d", i);
-               if (context->names[i].name) {
-                       audit_log_format(ab, " name=");
+               audit_log_format(ab, " name=");
+               if (context->names[i].name)
                        audit_log_untrustedstring(ab, context->names[i].name);
-               }
-               audit_log_format(ab, " flags=%x\n", context->names[i].flags);
-                        
-               if (context->names[i].ino != (unsigned long)-1)
-                       audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
-                                            " ouid=%u ogid=%u rdev=%02x:%02x",
-                                        context->names[i].ino,
-                                        MAJOR(context->names[i].dev),
-                                        MINOR(context->names[i].dev),
-                                        context->names[i].mode,
-                                        context->names[i].uid,
-                                        context->names[i].gid,
-                                        MAJOR(context->names[i].rdev),
+               else
+                       audit_log_format(ab, "(null)");
+               if (pino != (unsigned long)-1)
+                       audit_log_format(ab, " parent=%lu",  pino);
+               if (ino != (unsigned long)-1)
+                       audit_log_format(ab, " inode=%lu",  ino);
+               if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1))
+                       audit_log_format(ab, " dev=%02x:%02x mode=%#o" 
+                                        " ouid=%u ogid=%u rdev=%02x:%02x", 
+                                        MAJOR(context->names[i].dev), 
+                                        MINOR(context->names[i].dev), 
+                                        context->names[i].mode, 
+                                        context->names[i].uid, 
+                                        context->names[i].gid, 
+                                        MAJOR(context->names[i].rdev), 
                                         MINOR(context->names[i].rdev));
+               if (context->names[i].ctx) {
+                       audit_log_format(ab, " obj=%s",
+                                       context->names[i].ctx);
+               }
                audit_log_end(ab);
        }
  }
  
- /* Free a per-task audit context.  Called from copy_process and
-  * __put_task_struct. */
+ /**
+  * audit_free - free a per-task audit context
+  * @tsk: task whose audit context block to free
+  *
+  * Called from copy_process and __put_task_struct.
+  */
  void audit_free(struct task_struct *tsk)
  {
        struct audit_context *context;
  
-       task_lock(tsk);
+       /*
+        * No need to lock the task - when we execute audit_free()
+        * then the task has no external references anymore, and
+        * we are tearing it down. (The locking also confuses
+        * DEBUG_LOCKDEP - this freeing may occur in softirq
+        * contexts as well, via RCU.)
+        */
        context = audit_get_context(tsk, 0, 0);
-       task_unlock(tsk);
        if (likely(!context))
                return;
  
        audit_free_context(context);
  }
  
- /* Fill in audit context at syscall entry.  This only happens if the
+ /**
+  * audit_syscall_entry - fill in an audit record at syscall entry
+  * @tsk: task being audited
+  * @arch: architecture type
+  * @major: major syscall type (function)
+  * @a1: additional syscall register 1
+  * @a2: additional syscall register 2
+  * @a3: additional syscall register 3
+  * @a4: additional syscall register 4
+  *
+  * Fill in audit context at syscall entry.  This only happens if the
   * audit context was created when the task was created and the state or
   * filters demand the audit context be built.  If the state from the
   * per-task filter or from the per-syscall filter is AUDIT_RECORD_CONTEXT,
   * then the record will be written at syscall exit time (otherwise, it
   * will only be written if another part of the kernel requests that it
-  * be written). */
+  * be written).
+  */
  void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
                         unsigned long a1, unsigned long a2,
                         unsigned long a3, unsigned long a4)
  
        BUG_ON(!context);
  
-       /* This happens only on certain architectures that make system
+       /*
+        * This happens only on certain architectures that make system
         * calls in kernel_thread via the entry.S interface, instead of
         * with direct calls.  (If you are porting to a new
         * architecture, hitting this condition can indicate that you
         *
         * i386     no
         * x86_64   no
 -       * ppc64    yes (see arch/ppc64/kernel/misc.S)
 +       * ppc64    yes (see arch/powerpc/platforms/iseries/misc.S)
         *
         * This also happens with vm86 emulation in a non-nested manner
         * (entries without exits), so this case must be caught.
        if (context->in_syscall) {
                struct audit_context *newctx;
  
- #if defined(__NR_vm86) && defined(__NR_vm86old)
-               /* vm86 mode should only be entered once */
-               if (major == __NR_vm86 || major == __NR_vm86old)
-                       return;
- #endif
  #if AUDIT_DEBUG
                printk(KERN_ERR
                       "audit(:%d) pid=%d in syscall=%d;"
        context->auditable  = !!(state == AUDIT_RECORD_CONTEXT);
  }
  
- /* Tear down after system call.  If the audit context has been marked as
+ /**
+  * audit_syscall_exit - deallocate audit context after a system call
+  * @tsk: task being audited
+  * @valid: success/failure flag
+  * @return_code: syscall return value
+  *
+  * Tear down after system call.  If the audit context has been marked as
   * auditable (either because of the AUDIT_RECORD_CONTEXT state from
   * filtering, or because some other part of the kernel write an audit
   * message), then write out the syscall information.  In call cases,
-  * free the names stored from getname(). */
+  * free the names stored from getname().
+  */
  void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
  {
        struct audit_context *context;
        put_task_struct(tsk);
  }
  
- /* Add a name to the list.  Called from fs/namei.c:getname(). */
+ /**
+  * audit_getname - add a name to the list
+  * @name: name to add
+  *
+  * Add a name to the list of audit names for this context.
+  * Called from fs/namei.c:getname().
+  */
  void audit_getname(const char *name)
  {
        struct audit_context *context = current->audit_context;
                
  }
  
- /* Intercept a putname request.  Called from
-  * include/linux/fs.h:putname().  If we have stored the name from
-  * getname in the audit context, then we delay the putname until syscall
-  * exit. */
+ /* audit_putname - intercept a putname request
+  * @name: name to intercept and delay for putname
+  *
+  * If we have stored the name from getname in the audit context,
+  * then we delay the putname until syscall exit.
+  * Called from include/linux/fs.h:putname().
+  */
  void audit_putname(const char *name)
  {
        struct audit_context *context = current->audit_context;
                        for (i = 0; i < context->name_count; i++)
                                printk(KERN_ERR "name[%d] = %p = %s\n", i,
                                       context->names[i].name,
-                                      context->names[i].name);
+                                      context->names[i].name ?: "(null)");
                }
  #endif
                __putname(name);
  #endif
  }
  
- /* Store the inode and device from a lookup.  Called from
-  * fs/namei.c:path_lookup(). */
- void audit_inode(const char *name, const struct inode *inode, unsigned flags)
+ void audit_inode_context(int idx, const struct inode *inode)
+ {
+       struct audit_context *context = current->audit_context;
+       const char *suffix = security_inode_xattr_getsuffix();
+       char *ctx = NULL;
+       int len = 0;
+       if (!suffix)
+               goto ret;
+       len = security_inode_getsecurity(inode, suffix, NULL, 0, 0);
+       if (len == -EOPNOTSUPP)
+               goto ret;
+       if (len < 0) 
+               goto error_path;
+       ctx = kmalloc(len, GFP_KERNEL);
+       if (!ctx) 
+               goto error_path;
+       len = security_inode_getsecurity(inode, suffix, ctx, len, 0);
+       if (len < 0)
+               goto error_path;
+       kfree(context->names[idx].ctx);
+       context->names[idx].ctx = ctx;
+       goto ret;
+ error_path:
+       if (ctx)
+               kfree(ctx);
+       audit_panic("error in audit_inode_context");
+ ret:
+       return;
+ }
+ /**
+  * audit_inode - store the inode and device from a lookup
+  * @name: name being audited
+  * @inode: inode being audited
+  * @flags: lookup flags (as used in path_lookup())
+  *
+  * Called from fs/namei.c:path_lookup().
+  */
+ void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
  {
        int idx;
        struct audit_context *context = current->audit_context;
                ++context->ino_count;
  #endif
        }
-       context->names[idx].flags = flags;
-       context->names[idx].ino   = inode->i_ino;
        context->names[idx].dev   = inode->i_sb->s_dev;
        context->names[idx].mode  = inode->i_mode;
        context->names[idx].uid   = inode->i_uid;
        context->names[idx].gid   = inode->i_gid;
        context->names[idx].rdev  = inode->i_rdev;
+       audit_inode_context(idx, inode);
+       if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && 
+           (strcmp(name, ".") != 0)) {
+               context->names[idx].ino   = (unsigned long)-1;
+               context->names[idx].pino  = inode->i_ino;
+       } else {
+               context->names[idx].ino   = inode->i_ino;
+               context->names[idx].pino  = (unsigned long)-1;
+       }
+ }
+ /**
+  * audit_inode_child - collect inode info for created/removed objects
+  * @dname: inode's dentry name
+  * @inode: inode being audited
+  * @pino: inode number of dentry parent
+  *
+  * For syscalls that create or remove filesystem objects, audit_inode
+  * can only collect information for the filesystem object's parent.
+  * This call updates the audit context with the child's information.
+  * Syscalls that create a new filesystem object must be hooked after
+  * the object is created.  Syscalls that remove a filesystem object
+  * must be hooked prior, in order to capture the target inode during
+  * unsuccessful attempts.
+  */
+ void __audit_inode_child(const char *dname, const struct inode *inode,
+                        unsigned long pino)
+ {
+       int idx;
+       struct audit_context *context = current->audit_context;
+       if (!context->in_syscall)
+               return;
+       /* determine matching parent */
+       if (dname)
+               for (idx = 0; idx < context->name_count; idx++)
+                       if (context->names[idx].pino == pino) {
+                               const char *n;
+                               const char *name = context->names[idx].name;
+                               int dlen = strlen(dname);
+                               int nlen = name ? strlen(name) : 0;
+                               if (nlen < dlen)
+                                       continue;
+                               
+                               /* disregard trailing slashes */
+                               n = name + nlen - 1;
+                               while ((*n == '/') && (n > name))
+                                       n--;
+                               /* find last path component */
+                               n = n - dlen + 1;
+                               if (n < name)
+                                       continue;
+                               else if (n > name) {
+                                       if (*--n != '/')
+                                               continue;
+                                       else
+                                               n++;
+                               }
+                               if (strncmp(n, dname, dlen) == 0)
+                                       goto update_context;
+                       }
+       /* catch-all in case match not found */
+       idx = context->name_count++;
+       context->names[idx].name  = NULL;
+       context->names[idx].pino  = pino;
+ #if AUDIT_DEBUG
+       context->ino_count++;
+ #endif
+ update_context:
+       if (inode) {
+               context->names[idx].ino   = inode->i_ino;
+               context->names[idx].dev   = inode->i_sb->s_dev;
+               context->names[idx].mode  = inode->i_mode;
+               context->names[idx].uid   = inode->i_uid;
+               context->names[idx].gid   = inode->i_gid;
+               context->names[idx].rdev  = inode->i_rdev;
+               audit_inode_context(idx, inode);
+       }
  }
  
+ /**
+  * auditsc_get_stamp - get local copies of audit_context values
+  * @ctx: audit_context for the task
+  * @t: timespec to store time recorded in the audit_context
+  * @serial: serial value that is recorded in the audit_context
+  *
+  * Also sets the context as auditable.
+  */
  void auditsc_get_stamp(struct audit_context *ctx,
                       struct timespec *t, unsigned int *serial)
  {
        ctx->auditable = 1;
  }
  
+ /**
+  * audit_set_loginuid - set a task's audit_context loginuid
+  * @task: task whose audit context is being modified
+  * @loginuid: loginuid value
+  *
+  * Returns 0.
+  *
+  * Called (set) from fs/proc/base.c::proc_loginuid_write().
+  */
  int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
  {
        if (task->audit_context) {
        return 0;
  }
  
+ /**
+  * audit_get_loginuid - get the loginuid for an audit_context
+  * @ctx: the audit_context
+  *
+  * Returns the context's loginuid or -1 if @ctx is NULL.
+  */
  uid_t audit_get_loginuid(struct audit_context *ctx)
  {
        return ctx ? ctx->loginuid : -1;
  }
  
- int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+ static char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+ {
+       struct audit_context *context = current->audit_context;
+       char *ctx = NULL;
+       int len = 0;
+       if (likely(!context))
+               return NULL;
+       len = security_ipc_getsecurity(ipcp, NULL, 0);
+       if (len == -EOPNOTSUPP)
+               goto ret;
+       if (len < 0)
+               goto error_path;
+       ctx = kmalloc(len, GFP_ATOMIC);
+       if (!ctx)
+               goto error_path;
+       len = security_ipc_getsecurity(ipcp, ctx, len);
+       if (len < 0)
+               goto error_path;
+       return ctx;
+ error_path:
+       kfree(ctx);
+       audit_panic("error in audit_ipc_context");
+ ret:
+       return NULL;
+ }
+ /**
+  * audit_ipc_perms - record audit data for ipc
+  * @qbytes: msgq bytes
+  * @uid: msgq user id
+  * @gid: msgq group id
+  * @mode: msgq mode (permissions)
+  *
+  * 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)
  {
        struct audit_aux_data_ipcctl *ax;
        struct audit_context *context = current->audit_context;
        if (likely(!context))
                return 0;
  
-       ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+       ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
        if (!ax)
                return -ENOMEM;
  
        ax->uid = uid;
        ax->gid = gid;
        ax->mode = mode;
+       ax->ctx = audit_ipc_context(ipcp);
  
        ax->d.type = AUDIT_IPC;
        ax->d.next = context->aux;
        return 0;
  }
  
+ /**
+  * audit_socketcall - record audit data for sys_socketcall
+  * @nargs: number of args
+  * @args: args array
+  *
+  * Returns 0 for success or NULL context or < 0 on error.
+  */
  int audit_socketcall(int nargs, unsigned long *args)
  {
        struct audit_aux_data_socketcall *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
+  *
+  * Returns 0 for success or NULL context or < 0 on error.
+  */
  int audit_sockaddr(int len, void *a)
  {
        struct audit_aux_data_sockaddr *ax;
        return 0;
  }
  
+ /**
+  * audit_avc_path - record the granting or denial of permissions
+  * @dentry: dentry to record
+  * @mnt: mnt to record
+  *
+  * Returns 0 for success or NULL context or < 0 on error.
+  *
+  * Called from security/selinux/avc.c::avc_audit()
+  */
  int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
  {
        struct audit_aux_data_path *ax;
        return 0;
  }
  
+ /**
+  * audit_signal_info - record signal info for shutting down audit subsystem
+  * @sig: signal value
+  * @t: task being signaled
+  *
+  * If the audit subsystem is being terminated, record the task (pid)
+  * and uid that is doing that.
+  */
  void audit_signal_info(int sig, struct task_struct *t)
  {
        extern pid_t audit_sig_pid;
                }
        }
  }
diff --combined net/core/dev.c
index e0489ca731c57f17dda1ce30cfc7747098c4e221,e9f84a66ce8140f3f03579d471e2f8e5317bd1ab..8e1dc3051222f23e06b70025f006bb6256ab5194
@@@ -81,7 -81,6 +81,7 @@@
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/sched.h>
 +#include <linux/mutex.h>
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/socket.h>
  #include <linux/netpoll.h>
  #include <linux/rcupdate.h>
  #include <linux/delay.h>
 -#ifdef CONFIG_NET_RADIO
 -#include <linux/wireless.h>           /* Note : will define WIRELESS_EXT */
 +#include <linux/wireless.h>
  #include <net/iw_handler.h>
 -#endif        /* CONFIG_NET_RADIO */
  #include <asm/current.h>
+ #include <linux/audit.h>
  
  /*
   *    The list of packet types we will receive (as opposed to discard)
@@@ -977,12 -979,7 +978,12 @@@ int register_netdevice_notifier(struct 
  
  int unregister_netdevice_notifier(struct notifier_block *nb)
  {
 -      return notifier_chain_unregister(&netdev_chain, nb);
 +      int err;
 +
 +      rtnl_lock();
 +      err = notifier_chain_unregister(&netdev_chain, nb);
 +      rtnl_unlock();
 +      return err;
  }
  
  /**
@@@ -1452,29 -1449,8 +1453,29 @@@ static inline struct net_device *skb_bo
  {
        struct net_device *dev = skb->dev;
  
 -      if (dev->master)
 +      if (dev->master) {
 +              /*
 +               * On bonding slaves other than the currently active
 +               * slave, suppress duplicates except for 802.3ad
 +               * ETH_P_SLOW and alb non-mcast/bcast.
 +               */
 +              if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
 +                      if (dev->master->priv_flags & IFF_MASTER_ALB) {
 +                              if (skb->pkt_type != PACKET_BROADCAST &&
 +                                  skb->pkt_type != PACKET_MULTICAST)
 +                                      goto keep;
 +                      }
 +
 +                      if (dev->master->priv_flags & IFF_MASTER_8023AD &&
 +                          skb->protocol == __constant_htons(ETH_P_SLOW))
 +                              goto keep;
 +              
 +                      kfree_skb(skb);
 +                      return NULL;
 +              }
 +keep:
                skb->dev = dev->master;
 +      }
  
        return dev;
  }
@@@ -1618,9 -1594,6 +1619,9 @@@ int netif_receive_skb(struct sk_buff *s
  
        orig_dev = skb_bond(skb);
  
 +      if (!orig_dev)
 +              return NET_RX_DROP;
 +
        __get_cpu_var(netdev_rx_stat).total++;
  
        skb->h.raw = skb->nh.raw = skb->data;
@@@ -1765,7 -1738,8 +1766,7 @@@ static void net_rx_action(struct softir
                if (dev->quota <= 0 || dev->poll(dev, &budget)) {
                        netpoll_poll_unlock(have);
                        local_irq_disable();
 -                      list_del(&dev->poll_list);
 -                      list_add_tail(&dev->poll_list, &queue->poll_list);
 +                      list_move_tail(&dev->poll_list, &queue->poll_list);
                        if (dev->quota < 0)
                                dev->quota += dev->weight;
                        else
@@@ -2055,7 -2029,7 +2056,7 @@@ static struct file_operations softnet_s
        .release = seq_release,
  };
  
 -#ifdef WIRELESS_EXT
 +#ifdef CONFIG_WIRELESS_EXT
  extern int wireless_proc_init(void);
  #else
  #define wireless_proc_init() 0
@@@ -2147,6 -2121,12 +2148,12 @@@ void dev_set_promiscuity(struct net_dev
                printk(KERN_INFO "device %s %s promiscuous mode\n",
                       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
                                                               "left");
+               audit_log(current->audit_context, GFP_ATOMIC,
+                       AUDIT_ANOM_PROMISCUOUS,
+                       "dev=%s prom=%d old_prom=%d auid=%u",
+                       dev->name, (dev->flags & IFF_PROMISC),
+                       (old_flags & IFF_PROMISC),
+                       audit_get_loginuid(current->audit_context)); 
        }
  }
  
@@@ -2179,20 -2159,12 +2186,20 @@@ unsigned dev_get_flags(const struct net
  
        flags = (dev->flags & ~(IFF_PROMISC |
                                IFF_ALLMULTI |
 -                              IFF_RUNNING)) | 
 +                              IFF_RUNNING |
 +                              IFF_LOWER_UP |
 +                              IFF_DORMANT)) |
                (dev->gflags & (IFF_PROMISC |
                                IFF_ALLMULTI));
  
 -      if (netif_running(dev) && netif_carrier_ok(dev))
 -              flags |= IFF_RUNNING;
 +      if (netif_running(dev)) {
 +              if (netif_oper_up(dev))
 +                      flags |= IFF_RUNNING;
 +              if (netif_carrier_ok(dev))
 +                      flags |= IFF_LOWER_UP;
 +              if (netif_dormant(dev))
 +                      flags |= IFF_DORMANT;
 +      }
  
        return flags;
  }
@@@ -2471,9 -2443,9 +2478,9 @@@ int dev_ioctl(unsigned int cmd, void __
         */
  
        if (cmd == SIOCGIFCONF) {
 -              rtnl_shlock();
 +              rtnl_lock();
                ret = dev_ifconf((char __user *) arg);
 -              rtnl_shunlock();
 +              rtnl_unlock();
                return ret;
        }
        if (cmd == SIOCGIFNAME)
                                        ret = -EFAULT;
                                return ret;
                        }
 -#ifdef WIRELESS_EXT
 +#ifdef CONFIG_WIRELESS_EXT
                        /* Take care of Wireless Extensions */
                        if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
                                /* If command is `set a parameter', or
                                        ret = -EFAULT;
                                return ret;
                        }
 -#endif        /* WIRELESS_EXT */
 +#endif        /* CONFIG_WIRELESS_EXT */
                        return -EINVAL;
        }
  }
@@@ -2882,7 -2854,7 +2889,7 @@@ static void netdev_wait_allrefs(struct 
        rebroadcast_time = warning_time = jiffies;
        while (atomic_read(&dev->refcnt) != 0) {
                if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
 -                      rtnl_shlock();
 +                      rtnl_lock();
  
                        /* Rebroadcast unregister notification */
                        notifier_call_chain(&netdev_chain,
                                linkwatch_run_queue();
                        }
  
 -                      rtnl_shunlock();
 +                      __rtnl_unlock();
  
                        rebroadcast_time = jiffies;
                }
   * 2) Since we run with the RTNL semaphore not held, we can sleep
   *    safely in order to wait for the netdev refcnt to drop to zero.
   */
 -static DECLARE_MUTEX(net_todo_run_mutex);
 +static DEFINE_MUTEX(net_todo_run_mutex);
  void netdev_run_todo(void)
  {
        struct list_head list = LIST_HEAD_INIT(list);
  
  
        /* Need to guard against multiple cpu's getting out of order. */
 -      down(&net_todo_run_mutex);
 +      mutex_lock(&net_todo_run_mutex);
  
        /* Not safe to do outside the semaphore.  We must not return
         * until all unregister events invoked by the local processor
        }
  
  out:
 -      up(&net_todo_run_mutex);
 +      mutex_unlock(&net_todo_run_mutex);
  }
  
  /**
diff --combined security/dummy.c
index a678f094b72dcc8b909d89cade196407271cc483,0a553d39729f828f17663a810b85569a857a8507..fd99429278e905e4ec33558d8e31895928359bb6
@@@ -378,7 -378,7 +378,7 @@@ static int dummy_inode_removexattr (str
        return 0;
  }
  
- static int dummy_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+ static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
  {
        return -EOPNOTSUPP;
  }
@@@ -393,6 -393,11 +393,11 @@@ static int dummy_inode_listsecurity(str
        return 0;
  }
  
+ static const char *dummy_inode_xattr_getsuffix(void)
+ {
+       return NULL;
+ }
  static int dummy_file_permission (struct file *file, int mask)
  {
        return 0;
@@@ -558,6 -563,11 +563,11 @@@ static int dummy_ipc_permission (struc
        return 0;
  }
  
+ static int dummy_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+ {
+       return -EOPNOTSUPP;
+ }
  static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
  {
        return 0;
@@@ -763,14 -773,8 +773,14 @@@ static int dummy_socket_sock_rcv_skb (s
        return 0;
  }
  
 -static int dummy_socket_getpeersec(struct socket *sock, char __user *optval,
 -                                 int __user *optlen, unsigned len)
 +static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 +                                        int __user *optlen, unsigned len)
 +{
 +      return -ENOPROTOOPT;
 +}
 +
 +static int dummy_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
 +                                       u32 *seclen)
  {
        return -ENOPROTOOPT;
  }
@@@ -931,6 -935,7 +941,7 @@@ void security_fixup_ops (struct securit
        set_to_dummy_if_null(ops, inode_getxattr);
        set_to_dummy_if_null(ops, inode_listxattr);
        set_to_dummy_if_null(ops, inode_removexattr);
+       set_to_dummy_if_null(ops, inode_xattr_getsuffix);
        set_to_dummy_if_null(ops, inode_getsecurity);
        set_to_dummy_if_null(ops, inode_setsecurity);
        set_to_dummy_if_null(ops, inode_listsecurity);
        set_to_dummy_if_null(ops, task_reparent_to_init);
        set_to_dummy_if_null(ops, task_to_inode);
        set_to_dummy_if_null(ops, ipc_permission);
+       set_to_dummy_if_null(ops, ipc_getsecurity);
        set_to_dummy_if_null(ops, msg_msg_alloc_security);
        set_to_dummy_if_null(ops, msg_msg_free_security);
        set_to_dummy_if_null(ops, msg_queue_alloc_security);
        set_to_dummy_if_null(ops, socket_getsockopt);
        set_to_dummy_if_null(ops, socket_shutdown);
        set_to_dummy_if_null(ops, socket_sock_rcv_skb);
 -      set_to_dummy_if_null(ops, socket_getpeersec);
 +      set_to_dummy_if_null(ops, socket_getpeersec_stream);
 +      set_to_dummy_if_null(ops, socket_getpeersec_dgram);
        set_to_dummy_if_null(ops, sk_alloc_security);
        set_to_dummy_if_null(ops, sk_free_security);
        set_to_dummy_if_null(ops, sk_getsid);
diff --combined security/selinux/hooks.c
index ccaf988f37292876fa9bbef366ed7d36cf508c48,81b726b1a41919ba72ea106e44889644e207f2ff..b61b9554bc27c1d9eec70e3bce7e6a4f020d2345
@@@ -117,8 -117,32 +117,34 @@@ static struct security_operations *seco
  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)
@@@ -148,11 -172,10 +174,11 @@@ static int inode_alloc_security(struct 
        struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
  
 -      isec = kzalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
 +      isec = kmem_cache_alloc(sel_inode_cache, SLAB_KERNEL);
        if (!isec)
                return -ENOMEM;
  
 +      memset(isec, 0, sizeof(*isec));
        init_MUTEX(&isec->sem);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
@@@ -175,7 -198,7 +201,7 @@@ static void inode_free_security(struct 
        spin_unlock(&sbsec->isec_lock);
  
        inode->i_security = NULL;
 -      kfree(isec);
 +      kmem_cache_free(sel_inode_cache, isec);
  }
  
  static int file_alloc_security(struct file *file)
@@@ -1932,6 -1955,7 +1958,6 @@@ static int selinux_inode_init_security(
        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;
        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;
  
        inode_security_set_sid(inode, newsid);
  
 -      if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
 +      if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
                return -EOPNOTSUPP;
  
        if (name) {
@@@ -2210,6 -2235,11 +2236,11 @@@ static int selinux_inode_removexattr (s
        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
   *
   * Permission check is handled by selinux_inode_getxattr hook.
   */
- static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+ static int selinux_inode_getsecurity(const 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)) {
-               rc = -EOPNOTSUPP;
-               goto out;
-       }
-       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 (strcmp(name, XATTR_SELINUX_SUFFIX))
+               return -EOPNOTSUPP;
  
-       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;
+       return selinux_getsecurity(isec->sid, buffer, size);
  }
  
  static int selinux_inode_setsecurity(struct inode *inode, const char *name,
        return err;
  }
  
 -static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
 -                                   int __user *optlen, unsigned len)
 +static int selinux_socket_getpeersec_stream(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 (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
 +
 +      /* 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 {
                err = -ENOPROTOOPT;
                goto out;
        }
  
 -      ssec = sock->sk->sk_security;
 -      
 -      err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
 +      err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
 +
        if (err)
                goto out;
  
        return err;
  }
  
 +static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
 +{
 +      int err = 0;
 +      u32 peer_sid = selinux_socket_getpeer_dgram(skb);
 +
 +      if (peer_sid == SECSID_NULL)
 +              return -EINVAL;
 +
 +      err = security_sid_to_context(peer_sid, secdata, seclen);
 +      if (err)
 +              return err;
 +
 +      return 0;
 +}
 +
 +
 +
  static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
  {
        return sk_alloc_security(sk, family, priority);
@@@ -4054,6 -4020,13 +4052,13 @@@ static int selinux_ipc_permission(struc
        return ipc_has_perm(ipcp, av);
  }
  
+ static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+ {
+       struct ipc_security_struct *isec = ipcp->security;
+       return selinux_getsecurity(isec->sid, buffer, size);
+ }
  /* module stacking operations */
  static int selinux_register_security (const char *name, struct security_operations *ops)
  {
@@@ -4095,8 -4068,7 +4100,7 @@@ static int selinux_getprocattr(struct t
                               char *name, void *value, size_t size)
  {
        struct task_security_struct *tsec;
-       u32 sid, len;
-       char *context;
+       u32 sid;
        int error;
  
        if (current != p) {
                        return error;
        }
  
-       if (!size)
-               return -ERANGE;
        tsec = p->security;
  
        if (!strcmp(name, "current"))
        if (!sid)
                return 0;
  
-       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;
+       return selinux_getsecurity(sid, value, size);
  }
  
  static int selinux_setprocattr(struct task_struct *p,
@@@ -4291,6 -4251,7 +4283,7 @@@ static struct security_operations selin
        .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,
        .task_to_inode =                selinux_task_to_inode,
  
        .ipc_permission =               selinux_ipc_permission,
+       .ipc_getsecurity =              selinux_ipc_getsecurity,
  
        .msg_msg_alloc_security =       selinux_msg_msg_alloc_security,
        .msg_msg_free_security =        selinux_msg_msg_free_security,
        .socket_setsockopt =            selinux_socket_setsockopt,
        .socket_shutdown =              selinux_socket_shutdown,
        .socket_sock_rcv_skb =          selinux_socket_sock_rcv_skb,
 -      .socket_getpeersec =            selinux_socket_getpeersec,
 +      .socket_getpeersec_stream =     selinux_socket_getpeersec_stream,
 +      .socket_getpeersec_dgram =      selinux_socket_getpeersec_dgram,
        .sk_alloc_security =            selinux_sk_alloc_security,
        .sk_free_security =             selinux_sk_free_security,
        .sk_getsid =                    selinux_sk_getsid_security,
@@@ -4409,9 -4370,6 +4403,9 @@@ 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;
index 85e399259832cdebe9b201060a61877b3fed057b,73158244cf8c8f86498e22ff3905b6a6d562c8ea..b8f4d25cf33533d15ac51665674fa5dfaaf94bc2
@@@ -88,15 -88,8 +88,15 @@@ static struct nlmsg_perm nlmsg_xfrm_per
        { XFRM_MSG_DELPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
        { XFRM_MSG_GETPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_READ  },
        { XFRM_MSG_ALLOCSPI,    NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 +      { XFRM_MSG_ACQUIRE,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 +      { XFRM_MSG_EXPIRE,      NETLINK_XFRM_SOCKET__NLMSG_WRITE },
        { XFRM_MSG_UPDPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
        { XFRM_MSG_UPDSA,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 +      { XFRM_MSG_POLEXPIRE,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 +      { XFRM_MSG_FLUSHSA,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 +      { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 +      { XFRM_MSG_NEWAE,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
 +      { XFRM_MSG_GETAE,       NETLINK_XFRM_SOCKET__NLMSG_READ  },
  };
  
  static struct nlmsg_perm nlmsg_audit_perms[] =
        { AUDIT_LIST,           NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
        { AUDIT_ADD,            NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
        { AUDIT_DEL,            NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+       { AUDIT_LIST_RULES,     NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+       { AUDIT_ADD_RULE,       NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
+       { AUDIT_DEL_RULE,       NETLINK_AUDIT_SOCKET__NLMSG_WRITE    },
        { AUDIT_USER,           NETLINK_AUDIT_SOCKET__NLMSG_RELAY    },
        { AUDIT_SIGNAL_INFO,    NETLINK_AUDIT_SOCKET__NLMSG_READ     },
  };
@@@ -152,8 -148,10 +155,10 @@@ int selinux_nlmsg_lookup(u16 sclass, u1
                break;
  
        case SECCLASS_NETLINK_AUDIT_SOCKET:
-               if (nlmsg_type >= AUDIT_FIRST_USER_MSG &&
-                   nlmsg_type <= AUDIT_LAST_USER_MSG) {
+               if ((nlmsg_type >= AUDIT_FIRST_USER_MSG &&
+                    nlmsg_type <= AUDIT_LAST_USER_MSG) ||
+                   (nlmsg_type >= AUDIT_FIRST_USER_MSG2 &&
+                      nlmsg_type <= AUDIT_LAST_USER_MSG2)) {
                        *perm = NETLINK_AUDIT_SOCKET__NLMSG_RELAY;
                } else {
                        err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms,
index f5d78365488fc2728782342cdaa5d49fb39d1302,5eba6664eac0795523956e31af9405e86cd06409..a4efc966f065eae8599ee034a3ac760efca0d92f
  #include <linux/slab.h>
  #include <linux/vmalloc.h>
  #include <linux/fs.h>
 +#include <linux/mutex.h>
  #include <linux/init.h>
  #include <linux/string.h>
  #include <linux/security.h>
  #include <linux/major.h>
  #include <linux/seq_file.h>
  #include <linux/percpu.h>
+ #include <linux/audit.h>
  #include <asm/uaccess.h>
  #include <asm/semaphore.h>
  
@@@ -45,7 -45,7 +46,7 @@@ static int __init checkreqprot_setup(ch
  __setup("checkreqprot=", checkreqprot_setup);
  
  
 -static DECLARE_MUTEX(sel_sem);
 +static DEFINE_MUTEX(sel_mutex);
  
  /* global data for booleans */
  static struct dentry *bool_dir = NULL;
@@@ -127,6 -127,10 +128,10 @@@ static ssize_t sel_write_enforce(struc
                length = task_has_security(current, SECURITY__SETENFORCE);
                if (length)
                        goto out;
+               audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+                       "enforcing=%d old_enforcing=%d auid=%u", new_value, 
+                       selinux_enforcing,
+                       audit_get_loginuid(current->audit_context));
                selinux_enforcing = new_value;
                if (selinux_enforcing)
                        avc_ss_reset(0);
@@@ -177,6 -181,9 +182,9 @@@ static ssize_t sel_write_disable(struc
                length = selinux_disable();
                if (length < 0)
                        goto out;
+               audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+                       "selinux=0 auid=%u",
+                       audit_get_loginuid(current->audit_context));
        }
  
        length = count;
@@@ -231,7 -238,7 +239,7 @@@ static ssize_t sel_write_load(struct fi
        ssize_t length;
        void *data = NULL;
  
 -      down(&sel_sem);
 +      mutex_lock(&sel_mutex);
  
        length = task_has_security(current, SECURITY__LOAD_POLICY);
        if (length)
                length = ret;
        else
                length = count;
+       audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
+               "policy loaded auid=%u",
+               audit_get_loginuid(current->audit_context));
  out:
 -      up(&sel_sem);
 +      mutex_unlock(&sel_mutex);
        vfree(data);
        return length;
  }
@@@ -710,11 -720,12 +721,11 @@@ static ssize_t sel_read_bool(struct fil
  {
        char *page = NULL;
        ssize_t length;
 -      ssize_t end;
        ssize_t ret;
        int cur_enforcing;
        struct inode *inode;
  
 -      down(&sel_sem);
 +      mutex_lock(&sel_mutex);
  
        ret = -EFAULT;
  
  
        length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
                          bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
 -      if (length < 0) {
 -              ret = length;
 -              goto out;
 -      }
 -
 -      if (*ppos >= length) {
 -              ret = 0;
 -              goto out;
 -      }
 -      if (count + *ppos > length)
 -              count = length - *ppos;
 -      end = count + *ppos;
 -      if (copy_to_user(buf, (char *) page + *ppos, count)) {
 -              ret = -EFAULT;
 -              goto out;
 -      }
 -      *ppos = end;
 -      ret = count;
 +      ret = simple_read_from_buffer(buf, count, ppos, page, length);
  out:
 -      up(&sel_sem);
 +      mutex_unlock(&sel_mutex);
        if (page)
                free_page((unsigned long)page);
        return ret;
@@@ -756,7 -784,7 +767,7 @@@ static ssize_t sel_write_bool(struct fi
        int new_value;
        struct inode *inode;
  
 -      down(&sel_sem);
 +      mutex_lock(&sel_mutex);
  
        length = task_has_security(current, SECURITY__SETBOOL);
        if (length)
        length = count;
  
  out:
 -      up(&sel_sem);
 +      mutex_unlock(&sel_mutex);
        if (page)
                free_page((unsigned long) page);
        return length;
@@@ -814,7 -842,7 +825,7 @@@ static ssize_t sel_commit_bools_write(s
        ssize_t length = -EFAULT;
        int new_value;
  
 -      down(&sel_sem);
 +      mutex_lock(&sel_mutex);
  
        length = task_has_security(current, SECURITY__SETBOOL);
        if (length)
        length = count;
  
  out:
 -      up(&sel_sem);
 +      mutex_unlock(&sel_mutex);
        if (page)
                free_page((unsigned long) page);
        return length;
@@@ -970,7 -998,7 +981,7 @@@ out
        return ret;
  err:
        kfree(values);
 -      d_genocide(dir);
 +      sel_remove_bools(dir);
        ret = -ENOMEM;
        goto out;
  }
@@@ -1151,38 -1179,37 +1162,38 @@@ static int sel_make_avc_files(struct de
                dentry = d_alloc_name(dir, files[i].name);
                if (!dentry) {
                        ret = -ENOMEM;
 -                      goto err;
 +                      goto out;
                }
  
                inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
                if (!inode) {
                        ret = -ENOMEM;
 -                      goto err;
 +                      goto out;
                }
                inode->i_fop = files[i].ops;
                d_add(dentry, inode);
        }
  out:
        return ret;
 -err:
 -      d_genocide(dir);
 -      goto out;
  }
  
 -static int sel_make_dir(struct super_block *sb, struct dentry *dentry)
 +static int sel_make_dir(struct inode *dir, struct dentry *dentry)
  {
        int ret = 0;
        struct inode *inode;
  
 -      inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
 +      inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO);
        if (!inode) {
                ret = -ENOMEM;
                goto out;
        }
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
 +      /* directory inodes start off with i_nlink == 2 (for "." entry) */
 +      inode->i_nlink++;
        d_add(dentry, inode);
 +      /* bump link count on parent directory, too */
 +      dir->i_nlink++;
  out:
        return ret;
  }
@@@ -1191,7 -1218,7 +1202,7 @@@ static int sel_fill_super(struct super_
  {
        int ret;
        struct dentry *dentry;
 -      struct inode *inode;
 +      struct inode *inode, *root_inode;
        struct inode_security_struct *isec;
  
        static struct tree_descr selinux_files[] = {
        };
        ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
        if (ret)
 -              return ret;
 +              goto err;
 +
 +      root_inode = sb->s_root->d_inode;
  
        dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME);
 -      if (!dentry)
 -              return -ENOMEM;
 +      if (!dentry) {
 +              ret = -ENOMEM;
 +              goto err;
 +      }
  
 -      inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
 -      if (!inode)
 -              goto out;
 -      inode->i_op = &simple_dir_inode_operations;
 -      inode->i_fop = &simple_dir_operations;
 -      d_add(dentry, inode);
 -      bool_dir = dentry;
 -      ret = sel_make_bools();
 +      ret = sel_make_dir(root_inode, dentry);
        if (ret)
 -              goto out;
 +              goto err;
 +
 +      bool_dir = dentry;
  
        dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
 -      if (!dentry)
 -              return -ENOMEM;
 +      if (!dentry) {
 +              ret = -ENOMEM;
 +              goto err;
 +      }
  
        inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
 -      if (!inode)
 -              goto out;
 +      if (!inode) {
 +              ret = -ENOMEM;
 +              goto err;
 +      }
        isec = (struct inode_security_struct*)inode->i_security;
        isec->sid = SECINITSID_DEVNULL;
        isec->sclass = SECCLASS_CHR_FILE;
        selinux_null = dentry;
  
        dentry = d_alloc_name(sb->s_root, "avc");
 -      if (!dentry)
 -              return -ENOMEM;
 +      if (!dentry) {
 +              ret = -ENOMEM;
 +              goto err;
 +      }
  
 -      ret = sel_make_dir(sb, dentry);
 +      ret = sel_make_dir(root_inode, dentry);
        if (ret)
 -              goto out;
 +              goto err;
  
        ret = sel_make_avc_files(dentry);
        if (ret)
 -              goto out;
 -
 -      return 0;
 +              goto err;
  out:
 -      dput(dentry);
 +      return ret;
 +err:
        printk(KERN_ERR "%s:  failed while creating inodes\n", __FUNCTION__);
 -      return -ENOMEM;
 +      goto out;
  }
  
  static struct super_block *sel_get_sb(struct file_system_type *fs_type,
index 63e0b7f29cb5c0f2160871a9cf3552603c066c90,d877cd16a81302faeffc348f014e03dbcd892ca5..61492485de84503f4ba87fff57326a3efde187a9
@@@ -27,8 -27,7 +27,8 @@@
  #include <linux/in.h>
  #include <linux/sched.h>
  #include <linux/audit.h>
 -#include <asm/semaphore.h>
 +#include <linux/mutex.h>
 +
  #include "flask.h"
  #include "avc.h"
  #include "avc_ss.h"
@@@ -49,9 -48,9 +49,9 @@@ static DEFINE_RWLOCK(policy_rwlock)
  #define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
  #define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
  
 -static DECLARE_MUTEX(load_sem);
 -#define LOAD_LOCK down(&load_sem)
 -#define LOAD_UNLOCK up(&load_sem)
 +static DEFINE_MUTEX(load_mutex);
 +#define LOAD_LOCK mutex_lock(&load_mutex)
 +#define LOAD_UNLOCK mutex_unlock(&load_mutex)
  
  static struct sidtab sidtab;
  struct policydb policydb;
@@@ -1759,19 -1758,22 +1759,22 @@@ int security_set_bools(int len, int *va
                goto out;
        }
  
-       printk(KERN_INFO "security: committed booleans { ");
        for (i = 0; i < len; i++) {
+               if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
+                       audit_log(current->audit_context, GFP_ATOMIC,
+                               AUDIT_MAC_CONFIG_CHANGE,
+                               "bool=%s val=%d old_val=%d auid=%u",
+                               policydb.p_bool_val_to_name[i],
+                               !!values[i],
+                               policydb.bool_val_to_struct[i]->state,
+                               audit_get_loginuid(current->audit_context));
+               }
                if (values[i]) {
                        policydb.bool_val_to_struct[i]->state = 1;
                } else {
                        policydb.bool_val_to_struct[i]->state = 0;
                }
-               if (i != 0)
-                       printk(", ");
-               printk("%s:%d", policydb.p_bool_val_to_name[i],
-                      policydb.bool_val_to_struct[i]->state);
        }
-       printk(" }\n");
  
        for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
                rc = evaluate_cond_node(&policydb, cur);