UBUNTU: Ubuntu-2.6.38-12.51
[linux-flexiantxendom0-natty.git] / security / security.c
index f0d96a6..fa4a25e 100644 (file)
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/security.h>
+#include <linux/ima.h>
 
 /* Boot-time LSM user choice */
-static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
+static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
+       CONFIG_DEFAULT_SECURITY;
+
+#if CONFIG_SECURITY_YAMA
+extern int yama_ptrace_access_check(struct task_struct *child,
+                                   unsigned int mode);
+extern int yama_path_link(struct dentry *old_dentry, struct path *new_dir,
+                         struct dentry *new_dentry);
+extern int yama_inode_follow_link(struct dentry *dentry,
+                                 struct nameidata *nameidata);
+extern void yama_task_free(struct task_struct *task);
+extern int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+                          unsigned long arg4, unsigned long arg5);
+#endif
 
 /* things that live in capability.c */
-extern struct security_operations default_security_ops;
-extern void security_fixup_ops(struct security_operations *ops);
+extern void __init security_fixup_ops(struct security_operations *ops);
 
-struct security_operations *security_ops;      /* Initialized to NULL */
+static struct security_operations *security_ops;
+static struct security_operations default_security_ops = {
+       .name   = "default",
+};
 
-/* amount of vm to protect from userspace access */
-unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR;
-
-static inline int verify(struct security_operations *ops)
+static inline int __init verify(struct security_operations *ops)
 {
        /* verify the security_operations structure exists */
        if (!ops)
@@ -64,6 +77,11 @@ int __init security_init(void)
        return 0;
 }
 
+void reset_security_ops(void)
+{
+       security_ops = &default_security_ops;
+}
+
 /* Save user chosen LSM */
 static int __init choose_lsm(char *str)
 {
@@ -82,19 +100,13 @@ __setup("security=", choose_lsm);
  *
  * Return true if:
  *     -The passed LSM is the one chosen by user at boot time,
- *     -or user didn't specify a specific LSM and we're the first to ask
- *      for registration permission,
- *     -or the passed LSM is currently loaded.
+ *     -or the passed LSM is configured as the default and the user did not
+ *      choose an alternate LSM at boot time.
  * Otherwise, return false.
  */
 int __init security_module_enable(struct security_operations *ops)
 {
-       if (!*chosen_lsm)
-               strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
-       else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
-               return 0;
-
-       return 1;
+       return !strcmp(ops->name, chosen_lsm);
 }
 
 /**
@@ -109,7 +121,7 @@ int __init security_module_enable(struct security_operations *ops)
  * If there is already a security module registered with the kernel,
  * an error will be returned.  Otherwise %0 is returned on success.
  */
-int register_security(struct security_operations *ops)
+int __init register_security(struct security_operations *ops)
 {
        if (verify(ops)) {
                printk(KERN_DEBUG "%s could not verify "
@@ -127,9 +139,15 @@ int register_security(struct security_operations *ops)
 
 /* Security operations */
 
-int security_ptrace_may_access(struct task_struct *child, unsigned int mode)
+int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
-       return security_ops->ptrace_may_access(child, mode);
+#if CONFIG_SECURITY_YAMA
+       int rc;
+       rc = yama_ptrace_access_check(child, mode);
+       if (rc || security_ops->ptrace_access_check == yama_ptrace_access_check)
+               return rc;
+#endif
+       return security_ops->ptrace_access_check(child, mode);
 }
 
 int security_ptrace_traceme(struct task_struct *parent)
@@ -154,19 +172,31 @@ int security_capset(struct cred *new, const struct cred *old,
                                    effective, inheritable, permitted);
 }
 
-int security_capable(struct task_struct *tsk, int cap)
+int security_capable(const struct cred *cred, int cap)
 {
-       return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT);
+       return security_ops->capable(current, cred, cap, SECURITY_CAP_AUDIT);
 }
 
-int security_capable_noaudit(struct task_struct *tsk, int cap)
+int security_real_capable(struct task_struct *tsk, int cap)
 {
-       return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT);
+       const struct cred *cred;
+       int ret;
+
+       cred = get_task_cred(tsk);
+       ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT);
+       put_cred(cred);
+       return ret;
 }
 
-int security_acct(struct file *file)
+int security_real_capable_noaudit(struct task_struct *tsk, int cap)
 {
-       return security_ops->acct(file);
+       const struct cred *cred;
+       int ret;
+
+       cred = get_task_cred(tsk);
+       ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT);
+       put_cred(cred);
+       return ret;
 }
 
 int security_sysctl(struct ctl_table *table, int op)
@@ -220,7 +250,12 @@ int security_bprm_set_creds(struct linux_binprm *bprm)
 
 int security_bprm_check(struct linux_binprm *bprm)
 {
-       return security_ops->bprm_check_security(bprm);
+       int ret;
+
+       ret = security_ops->bprm_check_security(bprm);
+       if (ret)
+               return ret;
+       return ima_bprm_check(bprm);
 }
 
 void security_bprm_committing_creds(struct linux_binprm *bprm)
@@ -254,9 +289,9 @@ int security_sb_copy_data(char *orig, char *copy)
 }
 EXPORT_SYMBOL(security_sb_copy_data);
 
-int security_sb_kern_mount(struct super_block *sb, void *data)
+int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
-       return security_ops->sb_kern_mount(sb, data);
+       return security_ops->sb_kern_mount(sb, flags, data);
 }
 
 int security_sb_show_options(struct seq_file *m, struct super_block *sb)
@@ -275,46 +310,16 @@ int security_sb_mount(char *dev_name, struct path *path,
        return security_ops->sb_mount(dev_name, path, type, flags, data);
 }
 
-int security_sb_check_sb(struct vfsmount *mnt, struct path *path)
-{
-       return security_ops->sb_check_sb(mnt, path);
-}
-
 int security_sb_umount(struct vfsmount *mnt, int flags)
 {
        return security_ops->sb_umount(mnt, flags);
 }
 
-void security_sb_umount_close(struct vfsmount *mnt)
-{
-       security_ops->sb_umount_close(mnt);
-}
-
-void security_sb_umount_busy(struct vfsmount *mnt)
-{
-       security_ops->sb_umount_busy(mnt);
-}
-
-void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data)
-{
-       security_ops->sb_post_remount(mnt, flags, data);
-}
-
-void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint)
-{
-       security_ops->sb_post_addmount(mnt, mountpoint);
-}
-
 int security_sb_pivotroot(struct path *old_path, struct path *new_path)
 {
        return security_ops->sb_pivotroot(old_path, new_path);
 }
 
-void security_sb_post_pivotroot(struct path *old_path, struct path *new_path)
-{
-       security_ops->sb_post_pivotroot(old_path, new_path);
-}
-
 int security_sb_set_mnt_opts(struct super_block *sb,
                                struct security_mnt_opts *opts)
 {
@@ -343,6 +348,7 @@ int security_inode_alloc(struct inode *inode)
 
 void security_inode_free(struct inode *inode)
 {
+       ima_inode_free(inode);
        security_ops->inode_free_security(inode);
 }
 
@@ -355,12 +361,112 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
 }
 EXPORT_SYMBOL(security_inode_init_security);
 
+#ifdef CONFIG_SECURITY_PATH
+int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+                       unsigned int dev)
+{
+       if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+               return 0;
+       return security_ops->path_mknod(dir, dentry, mode, dev);
+}
+EXPORT_SYMBOL(security_path_mknod);
+
+int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
+{
+       if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+               return 0;
+       return security_ops->path_mkdir(dir, dentry, mode);
+}
+EXPORT_SYMBOL(security_path_mkdir);
+
+int security_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+       if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+               return 0;
+       return security_ops->path_rmdir(dir, dentry);
+}
+EXPORT_SYMBOL(security_path_rmdir);
+
+int security_path_unlink(struct path *dir, struct dentry *dentry)
+{
+       if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+               return 0;
+       return security_ops->path_unlink(dir, dentry);
+}
+EXPORT_SYMBOL(security_path_unlink);
+
+int security_path_symlink(struct path *dir, struct dentry *dentry,
+                         const char *old_name)
+{
+       if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+               return 0;
+       return security_ops->path_symlink(dir, dentry, old_name);
+}
+EXPORT_SYMBOL(security_path_symlink);
+
+int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+                      struct dentry *new_dentry)
+{
+       if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
+               return 0;
+#if CONFIG_SECURITY_YAMA
+       int rc = yama_path_link(old_dentry, new_dir, new_dentry);
+       if (rc || security_ops->path_link == yama_path_link)
+               return rc;
+#endif
+       return security_ops->path_link(old_dentry, new_dir, new_dentry);
+}
+EXPORT_SYMBOL(security_path_link);
+
+int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
+                        struct path *new_dir, struct dentry *new_dentry)
+{
+       if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
+                    (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
+               return 0;
+       return security_ops->path_rename(old_dir, old_dentry, new_dir,
+                                        new_dentry);
+}
+EXPORT_SYMBOL(security_path_rename);
+
+int security_path_truncate(struct path *path)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_truncate(path);
+}
+EXPORT_SYMBOL(security_path_truncate);
+
+int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+                       mode_t mode)
+{
+       if (unlikely(IS_PRIVATE(dentry->d_inode)))
+               return 0;
+       return security_ops->path_chmod(dentry, mnt, mode);
+}
+EXPORT_SYMBOL(security_path_chmod);
+
+int security_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+       if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+               return 0;
+       return security_ops->path_chown(path, uid, gid);
+}
+EXPORT_SYMBOL(security_path_chown);
+
+int security_path_chroot(struct path *path)
+{
+       return security_ops->path_chroot(path);
+}
+#endif
+
 int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
 {
        if (unlikely(IS_PRIVATE(dir)))
                return 0;
        return security_ops->inode_create(dir, dentry, mode);
 }
+EXPORT_SYMBOL_GPL(security_inode_create);
 
 int security_inode_link(struct dentry *old_dentry, struct inode *dir,
                         struct dentry *new_dentry)
@@ -391,6 +497,7 @@ int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                return 0;
        return security_ops->inode_mkdir(dir, dentry, mode);
 }
+EXPORT_SYMBOL_GPL(security_inode_mkdir);
 
 int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
 {
@@ -422,11 +529,17 @@ int security_inode_readlink(struct dentry *dentry)
                return 0;
        return security_ops->inode_readlink(dentry);
 }
+EXPORT_SYMBOL(security_inode_readlink);
 
 int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        if (unlikely(IS_PRIVATE(dentry->d_inode)))
                return 0;
+#if CONFIG_SECURITY_YAMA
+       int rc = yama_inode_follow_link(dentry, nd);
+       if (rc || security_ops->inode_follow_link == yama_inode_follow_link)
+               return rc;
+#endif
        return security_ops->inode_follow_link(dentry, nd);
 }
 
@@ -436,6 +549,16 @@ int security_inode_permission(struct inode *inode, int mask)
                return 0;
        return security_ops->inode_permission(inode, mask);
 }
+EXPORT_SYMBOL(security_inode_permission);
+
+int security_inode_exec_permission(struct inode *inode, unsigned int flags)
+{
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+       if (flags)
+               return -ECHILD;
+       return security_ops->inode_permission(inode, MAY_EXEC);
+}
 
 int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
 {
@@ -452,13 +575,6 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
        return security_ops->inode_getattr(mnt, dentry);
 }
 
-void security_inode_delete(struct inode *inode)
-{
-       if (unlikely(IS_PRIVATE(inode)))
-               return;
-       security_ops->inode_delete(inode);
-}
-
 int security_inode_setxattr(struct dentry *dentry, const char *name,
                            const void *value, size_t size, int flags)
 {
@@ -509,14 +625,14 @@ int security_inode_killpriv(struct dentry *dentry)
 int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
 {
        if (unlikely(IS_PRIVATE(inode)))
-               return 0;
+               return -EOPNOTSUPP;
        return security_ops->inode_getsecurity(inode, name, buffer, alloc);
 }
 
 int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
 {
        if (unlikely(IS_PRIVATE(inode)))
-               return 0;
+               return -EOPNOTSUPP;
        return security_ops->inode_setsecurity(inode, name, value, size, flags);
 }
 
@@ -534,8 +650,15 @@ void security_inode_getsecid(const struct inode *inode, u32 *secid)
 
 int security_file_permission(struct file *file, int mask)
 {
-       return security_ops->file_permission(file, mask);
+       int ret;
+
+       ret = security_ops->file_permission(file, mask);
+       if (ret)
+               return ret;
+
+       return fsnotify_perm(file, mask);
 }
+EXPORT_SYMBOL(security_file_permission);
 
 int security_file_alloc(struct file *file)
 {
@@ -556,8 +679,14 @@ int security_file_mmap(struct file *file, unsigned long reqprot,
                        unsigned long prot, unsigned long flags,
                        unsigned long addr, unsigned long addr_only)
 {
-       return security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only);
+       int ret;
+
+       ret = security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only);
+       if (ret)
+               return ret;
+       return ima_file_mmap(file, prot);
 }
+EXPORT_SYMBOL(security_file_mmap);
 
 int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
                            unsigned long prot)
@@ -593,7 +722,13 @@ int security_file_receive(struct file *file)
 
 int security_dentry_open(struct file *file, const struct cred *cred)
 {
-       return security_ops->dentry_open(file, cred);
+       int ret;
+
+       ret = security_ops->dentry_open(file, cred);
+       if (ret)
+               return ret;
+
+       return fsnotify_perm(file, MAY_OPEN);
 }
 
 int security_task_create(unsigned long clone_flags)
@@ -601,6 +736,21 @@ int security_task_create(unsigned long clone_flags)
        return security_ops->task_create(clone_flags);
 }
 
+void security_task_free(struct task_struct *task)
+{
+#if CONFIG_SECURITY_YAMA
+       yama_task_free(task);
+       if (security_ops->task_free == yama_task_free)
+               return;
+#endif
+       security_ops->task_free(task);
+}
+
+int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       return security_ops->cred_alloc_blank(cred, gfp);
+}
+
 void security_cred_free(struct cred *cred)
 {
        security_ops->cred_free(cred);
@@ -611,9 +761,9 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
        return security_ops->cred_prepare(new, old, gfp);
 }
 
-void security_commit_creds(struct cred *new, const struct cred *old)
+void security_transfer_creds(struct cred *new, const struct cred *old)
 {
-       security_ops->cred_commit(new, old);
+       security_ops->cred_transfer(new, old);
 }
 
 int security_kernel_act_as(struct cred *new, u32 secid)
@@ -626,9 +776,9 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
        return security_ops->kernel_create_files_as(new, inode);
 }
 
-int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
+int security_kernel_module_request(char *kmod_name)
 {
-       return security_ops->task_setuid(id0, id1, id2, flags);
+       return security_ops->kernel_module_request(kmod_name);
 }
 
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
@@ -637,11 +787,6 @@ int security_task_fix_setuid(struct cred *new, const struct cred *old,
        return security_ops->task_fix_setuid(new, old, flags);
 }
 
-int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
-{
-       return security_ops->task_setgid(id0, id1, id2, flags);
-}
-
 int security_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return security_ops->task_setpgid(p, pgid);
@@ -663,11 +808,6 @@ void security_task_getsecid(struct task_struct *p, u32 *secid)
 }
 EXPORT_SYMBOL(security_task_getsecid);
 
-int security_task_setgroups(struct group_info *group_info)
-{
-       return security_ops->task_setgroups(group_info);
-}
-
 int security_task_setnice(struct task_struct *p, int nice)
 {
        return security_ops->task_setnice(p, nice);
@@ -683,15 +823,15 @@ int security_task_getioprio(struct task_struct *p)
        return security_ops->task_getioprio(p);
 }
 
-int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+int security_task_setrlimit(struct task_struct *p, unsigned int resource,
+               struct rlimit *new_rlim)
 {
-       return security_ops->task_setrlimit(resource, new_rlim);
+       return security_ops->task_setrlimit(p, resource, new_rlim);
 }
 
-int security_task_setscheduler(struct task_struct *p,
-                               int policy, struct sched_param *lp)
+int security_task_setscheduler(struct task_struct *p)
 {
-       return security_ops->task_setscheduler(p, policy, lp);
+       return security_ops->task_setscheduler(p);
 }
 
 int security_task_getscheduler(struct task_struct *p)
@@ -718,6 +858,12 @@ int security_task_wait(struct task_struct *p)
 int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                         unsigned long arg4, unsigned long arg5)
 {
+#if CONFIG_SECURITY_YAMA
+       int rc;
+       rc = yama_task_prctl(option, arg2, arg3, arg4, arg5);
+       if (rc != -ENOSYS || security_ops->task_prctl == yama_task_prctl)
+               return rc;
+#endif
        return security_ops->task_prctl(option, arg2, arg3, arg4, arg5);
 }
 
@@ -876,10 +1022,27 @@ void security_release_secctx(char *secdata, u32 seclen)
 }
 EXPORT_SYMBOL(security_release_secctx);
 
+int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_notifysecctx);
+
+int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_setsecctx);
+
+int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+       return security_ops->inode_getsecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_getsecctx);
+
 #ifdef CONFIG_SECURITY_NETWORK
 
-int security_unix_stream_connect(struct socket *sock, struct socket *other,
-                                struct sock *newsk)
+int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk)
 {
        return security_ops->unix_stream_connect(sock, other, newsk);
 }
@@ -923,11 +1086,6 @@ int security_socket_accept(struct socket *sock, struct socket *newsock)
        return security_ops->socket_accept(sock, newsock);
 }
 
-void security_socket_post_accept(struct socket *sock, struct socket *newsock)
-{
-       security_ops->socket_post_accept(sock, newsock);
-}
-
 int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
        return security_ops->socket_sendmsg(sock, msg, size);
@@ -1034,6 +1192,42 @@ void security_inet_conn_established(struct sock *sk,
        security_ops->inet_conn_established(sk, skb);
 }
 
+int security_secmark_relabel_packet(u32 secid)
+{
+       return security_ops->secmark_relabel_packet(secid);
+}
+EXPORT_SYMBOL(security_secmark_relabel_packet);
+
+void security_secmark_refcount_inc(void)
+{
+       security_ops->secmark_refcount_inc();
+}
+EXPORT_SYMBOL(security_secmark_refcount_inc);
+
+void security_secmark_refcount_dec(void)
+{
+       security_ops->secmark_refcount_dec();
+}
+EXPORT_SYMBOL(security_secmark_refcount_dec);
+
+int security_tun_dev_create(void)
+{
+       return security_ops->tun_dev_create();
+}
+EXPORT_SYMBOL(security_tun_dev_create);
+
+void security_tun_dev_post_create(struct sock *sk)
+{
+       return security_ops->tun_dev_post_create(sk);
+}
+EXPORT_SYMBOL(security_tun_dev_post_create);
+
+int security_tun_dev_attach(struct sock *sk)
+{
+       return security_ops->tun_dev_attach(sk);
+}
+EXPORT_SYMBOL(security_tun_dev_attach);
+
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM