Commit 832d30ca authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (38 commits)
  SELinux: Make selinux_kernel_create_files_as() shouldn't just always return 0
  TOMOYO: Protect find_task_by_vpid() with RCU.
  Security: add static to security_ops and default_security_ops variable
  selinux: libsepol: remove dead code in check_avtab_hierarchy_callback()
  TOMOYO: Remove __func__ from tomoyo_is_correct_path/domain
  security: fix a couple of sparse warnings
  TOMOYO: Remove unneeded parameter.
  TOMOYO: Use shorter names.
  TOMOYO: Use enum for index numbers.
  TOMOYO: Add garbage collector.
  TOMOYO: Add refcounter on domain structure.
  TOMOYO: Merge headers.
  TOMOYO: Add refcounter on string data.
  TOMOYO: Reduce lines by using common path for addition and deletion.
  selinux: fix memory leak in sel_make_bools
  TOMOYO: Extract bitfield
  syslog: clean up needless comment
  syslog: use defined constants instead of raw numbers
  syslog: distinguish between /proc/kmsg and syscalls
  selinux: allow MLS->non-MLS and vice versa upon policy reload
  ...
parents 3a5b27bf b4ccebdd
...@@ -12,37 +12,37 @@ ...@@ -12,37 +12,37 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/syslog.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
extern wait_queue_head_t log_wait; extern wait_queue_head_t log_wait;
extern int do_syslog(int type, char __user *bug, int count);
static int kmsg_open(struct inode * inode, struct file * file) static int kmsg_open(struct inode * inode, struct file * file)
{ {
return do_syslog(1,NULL,0); return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_FILE);
} }
static int kmsg_release(struct inode * inode, struct file * file) static int kmsg_release(struct inode * inode, struct file * file)
{ {
(void) do_syslog(0,NULL,0); (void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_FILE);
return 0; return 0;
} }
static ssize_t kmsg_read(struct file *file, char __user *buf, static ssize_t kmsg_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, NULL, 0)) if ((file->f_flags & O_NONBLOCK) &&
!do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE))
return -EAGAIN; return -EAGAIN;
return do_syslog(2, buf, count); return do_syslog(SYSLOG_ACTION_READ, buf, count, SYSLOG_FROM_FILE);
} }
static unsigned int kmsg_poll(struct file *file, poll_table *wait) static unsigned int kmsg_poll(struct file *file, poll_table *wait)
{ {
poll_wait(file, &log_wait, wait); poll_wait(file, &log_wait, wait);
if (do_syslog(9, NULL, 0)) if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE))
return POLLIN | POLLRDNORM; return POLLIN | POLLRDNORM;
return 0; return 0;
} }
......
...@@ -76,7 +76,7 @@ extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, ...@@ -76,7 +76,7 @@ extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
extern int cap_task_setioprio(struct task_struct *p, int ioprio); extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice); extern int cap_task_setnice(struct task_struct *p, int nice);
extern int cap_syslog(int type); extern int cap_syslog(int type, bool from_file);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
struct msghdr; struct msghdr;
...@@ -95,6 +95,8 @@ struct seq_file; ...@@ -95,6 +95,8 @@ struct seq_file;
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
extern int cap_netlink_recv(struct sk_buff *skb, int cap); extern int cap_netlink_recv(struct sk_buff *skb, int cap);
void reset_security_ops(void);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
extern unsigned long mmap_min_addr; extern unsigned long mmap_min_addr;
extern unsigned long dac_mmap_min_addr; extern unsigned long dac_mmap_min_addr;
...@@ -985,6 +987,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) ...@@ -985,6 +987,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Check permissions on incoming network packets. This hook is distinct * Check permissions on incoming network packets. This hook is distinct
* from Netfilter's IP input hooks since it is the first time that the * from Netfilter's IP input hooks since it is the first time that the
* incoming sk_buff @skb has been associated with a particular socket, @sk. * incoming sk_buff @skb has been associated with a particular socket, @sk.
* Must not sleep inside this hook because some callers hold spinlocks.
* @sk contains the sock (not socket) associated with the incoming sk_buff. * @sk contains the sock (not socket) associated with the incoming sk_buff.
* @skb contains the incoming network data. * @skb contains the incoming network data.
* @socket_getpeersec_stream: * @socket_getpeersec_stream:
...@@ -1348,6 +1351,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) ...@@ -1348,6 +1351,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* logging to the console. * logging to the console.
* See the syslog(2) manual page for an explanation of the @type values. * See the syslog(2) manual page for an explanation of the @type values.
* @type contains the type of action. * @type contains the type of action.
* @from_file indicates the context of action (if it came from /proc).
* Return 0 if permission is granted. * Return 0 if permission is granted.
* @settime: * @settime:
* Check permission to change the system time. * Check permission to change the system time.
...@@ -1462,7 +1466,7 @@ struct security_operations { ...@@ -1462,7 +1466,7 @@ struct security_operations {
int (*sysctl) (struct ctl_table *table, int op); int (*sysctl) (struct ctl_table *table, int op);
int (*quotactl) (int cmds, int type, int id, struct super_block *sb); int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
int (*quota_on) (struct dentry *dentry); int (*quota_on) (struct dentry *dentry);
int (*syslog) (int type); int (*syslog) (int type, bool from_file);
int (*settime) (struct timespec *ts, struct timezone *tz); int (*settime) (struct timespec *ts, struct timezone *tz);
int (*vm_enough_memory) (struct mm_struct *mm, long pages); int (*vm_enough_memory) (struct mm_struct *mm, long pages);
...@@ -1761,7 +1765,7 @@ int security_acct(struct file *file); ...@@ -1761,7 +1765,7 @@ int security_acct(struct file *file);
int security_sysctl(struct ctl_table *table, int op); int security_sysctl(struct ctl_table *table, int op);
int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quotactl(int cmds, int type, int id, struct super_block *sb);
int security_quota_on(struct dentry *dentry); int security_quota_on(struct dentry *dentry);
int security_syslog(int type); int security_syslog(int type, bool from_file);
int security_settime(struct timespec *ts, struct timezone *tz); int security_settime(struct timespec *ts, struct timezone *tz);
int security_vm_enough_memory(long pages); int security_vm_enough_memory(long pages);
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
...@@ -2007,9 +2011,9 @@ static inline int security_quota_on(struct dentry *dentry) ...@@ -2007,9 +2011,9 @@ static inline int security_quota_on(struct dentry *dentry)
return 0; return 0;
} }
static inline int security_syslog(int type) static inline int security_syslog(int type, bool from_file)
{ {
return cap_syslog(type); return cap_syslog(type, from_file);
} }
static inline int security_settime(struct timespec *ts, struct timezone *tz) static inline int security_settime(struct timespec *ts, struct timezone *tz)
......
/* Syslog internals
*
* Copyright 2010 Canonical, Ltd.
* Author: Kees Cook <kees.cook@canonical.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _LINUX_SYSLOG_H
#define _LINUX_SYSLOG_H
/* Close the log. Currently a NOP. */
#define SYSLOG_ACTION_CLOSE 0
/* Open the log. Currently a NOP. */
#define SYSLOG_ACTION_OPEN 1
/* Read from the log. */
#define SYSLOG_ACTION_READ 2
/* Read all messages remaining in the ring buffer. */
#define SYSLOG_ACTION_READ_ALL 3
/* Read and clear all messages remaining in the ring buffer */
#define SYSLOG_ACTION_READ_CLEAR 4
/* Clear ring buffer. */
#define SYSLOG_ACTION_CLEAR 5
/* Disable printk's to console */
#define SYSLOG_ACTION_CONSOLE_OFF 6
/* Enable printk's to console */
#define SYSLOG_ACTION_CONSOLE_ON 7
/* Set level of messages printed to console */
#define SYSLOG_ACTION_CONSOLE_LEVEL 8
/* Return number of unread characters in the log buffer */
#define SYSLOG_ACTION_SIZE_UNREAD 9
/* Return size of the log buffer */
#define SYSLOG_ACTION_SIZE_BUFFER 10
#define SYSLOG_FROM_CALL 0
#define SYSLOG_FROM_FILE 1
int do_syslog(int type, char __user *buf, int count, bool from_file);
#endif /* _LINUX_SYSLOG_H */
...@@ -135,7 +135,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, ...@@ -135,7 +135,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
if (pid && (pid != task_pid_vnr(current))) { if (pid && (pid != task_pid_vnr(current))) {
struct task_struct *target; struct task_struct *target;
read_lock(&tasklist_lock); rcu_read_lock();
target = find_task_by_vpid(pid); target = find_task_by_vpid(pid);
if (!target) if (!target)
...@@ -143,7 +143,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, ...@@ -143,7 +143,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
else else
ret = security_capget(target, pEp, pIp, pPp); ret = security_capget(target, pEp, pIp, pPp);
read_unlock(&tasklist_lock); rcu_read_unlock();
} else } else
ret = security_capget(current, pEp, pIp, pPp); ret = security_capget(current, pEp, pIp, pPp);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/kmsg_dump.h> #include <linux/kmsg_dump.h>
#include <linux/syslog.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -258,38 +259,23 @@ static inline void boot_delay_msec(void) ...@@ -258,38 +259,23 @@ static inline void boot_delay_msec(void)
} }
#endif #endif
/* int do_syslog(int type, char __user *buf, int len, bool from_file)
* Commands to do_syslog:
*
* 0 -- Close the log. Currently a NOP.
* 1 -- Open the log. Currently a NOP.
* 2 -- Read from the log.
* 3 -- Read all messages remaining in the ring buffer.
* 4 -- Read and clear all messages remaining in the ring buffer
* 5 -- Clear ring buffer.
* 6 -- Disable printk's to console
* 7 -- Enable printk's to console
* 8 -- Set level of messages printed to console
* 9 -- Return number of unread characters in the log buffer
* 10 -- Return size of the log buffer
*/
int do_syslog(int type, char __user *buf, int len)
{ {
unsigned i, j, limit, count; unsigned i, j, limit, count;
int do_clear = 0; int do_clear = 0;
char c; char c;
int error = 0; int error = 0;
error = security_syslog(type); error = security_syslog(type, from_file);
if (error) if (error)
return error; return error;
switch (type) { switch (type) {
case 0: /* Close log */ case SYSLOG_ACTION_CLOSE: /* Close log */
break; break;
case 1: /* Open log */ case SYSLOG_ACTION_OPEN: /* Open log */
break; break;
case 2: /* Read from log */ case SYSLOG_ACTION_READ: /* Read from log */
error = -EINVAL; error = -EINVAL;
if (!buf || len < 0) if (!buf || len < 0)
goto out; goto out;
...@@ -320,10 +306,12 @@ int do_syslog(int type, char __user *buf, int len) ...@@ -320,10 +306,12 @@ int do_syslog(int type, char __user *buf, int len)
if (!error) if (!error)
error = i; error = i;
break; break;
case 4: /* Read/clear last kernel messages */ /* Read/clear last kernel messages */
case SYSLOG_ACTION_READ_CLEAR:
do_clear = 1; do_clear = 1;
/* FALL THRU */ /* FALL THRU */
case 3: /* Read last kernel messages */ /* Read last kernel messages */
case SYSLOG_ACTION_READ_ALL:
error = -EINVAL; error = -EINVAL;
if (!buf || len < 0) if (!buf || len < 0)
goto out; goto out;
...@@ -376,21 +364,25 @@ int do_syslog(int type, char __user *buf, int len) ...@@ -376,21 +364,25 @@ int do_syslog(int type, char __user *buf, int len)
} }
} }
break; break;
case 5: /* Clear ring buffer */ /* Clear ring buffer */
case SYSLOG_ACTION_CLEAR:
logged_chars = 0; logged_chars = 0;
break; break;
case 6: /* Disable logging to console */ /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_OFF:
if (saved_console_loglevel == -1) if (saved_console_loglevel == -1)
saved_console_loglevel = console_loglevel; saved_console_loglevel = console_loglevel;
console_loglevel = minimum_console_loglevel; console_loglevel = minimum_console_loglevel;
break; break;
case 7: /* Enable logging to console */ /* Enable logging to console */
case SYSLOG_ACTION_CONSOLE_ON:
if (saved_console_loglevel != -1) { if (saved_console_loglevel != -1) {
console_loglevel = saved_console_loglevel; console_loglevel = saved_console_loglevel;
saved_console_loglevel = -1; saved_console_loglevel = -1;
} }
break; break;
case 8: /* Set level of messages printed to console */ /* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
error = -EINVAL; error = -EINVAL;
if (len < 1 || len > 8) if (len < 1 || len > 8)
goto out; goto out;
...@@ -401,10 +393,12 @@ int do_syslog(int type, char __user *buf, int len) ...@@ -401,10 +393,12 @@ int do_syslog(int type, char __user *buf, int len)
saved_console_loglevel = -1; saved_console_loglevel = -1;
error = 0; error = 0;
break; break;
case 9: /* Number of chars in the log buffer */ /* Number of chars in the log buffer */
case SYSLOG_ACTION_SIZE_UNREAD:
error = log_end - log_start; error = log_end - log_start;
break; break;
case 10: /* Size of the log buffer */ /* Size of the log buffer */
case SYSLOG_ACTION_SIZE_BUFFER:
error = log_buf_len; error = log_buf_len;
break; break;
default: default:
...@@ -417,7 +411,7 @@ int do_syslog(int type, char __user *buf, int len) ...@@ -417,7 +411,7 @@ int do_syslog(int type, char __user *buf, int len)
SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
{ {
return do_syslog(type, buf, len); return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
} }
/* /*
......
...@@ -906,10 +906,6 @@ static void cap_audit_rule_free(void *lsmrule) ...@@ -906,10 +906,6 @@ static void cap_audit_rule_free(void *lsmrule)
} }
#endif /* CONFIG_AUDIT */ #endif /* CONFIG_AUDIT */
struct security_operations default_security_ops = {
.name = "default",
};
#define set_to_cap_if_null(ops, function) \ #define set_to_cap_if_null(ops, function) \
do { \ do { \
if (!ops->function) { \ if (!ops->function) { \
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/prctl.h> #include <linux/prctl.h>
#include <linux/securebits.h> #include <linux/securebits.h>
#include <linux/syslog.h>
/* /*
* If a non-root user executes a setuid-root binary in * If a non-root user executes a setuid-root binary in
...@@ -888,13 +889,17 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, ...@@ -888,13 +889,17 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
/** /**
* cap_syslog - Determine whether syslog function is permitted * cap_syslog - Determine whether syslog function is permitted
* @type: Function requested * @type: Function requested
* @from_file: Whether this request came from an open file (i.e. /proc)
* *
* Determine whether the current process is permitted to use a particular * Determine whether the current process is permitted to use a particular
* syslog function, returning 0 if permission is granted, -ve if not. * syslog function, returning 0 if permission is granted, -ve if not.
*/ */
int cap_syslog(int type) int cap_syslog(int type, bool from_file)
{ {
if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) if (type != SYSLOG_ACTION_OPEN && from_file)
return 0;
if ((type != SYSLOG_ACTION_READ_ALL &&
type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
return 0; return 0;
} }
......
...@@ -23,10 +23,12 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = ...@@ -23,10 +23,12 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
CONFIG_DEFAULT_SECURITY; CONFIG_DEFAULT_SECURITY;
/* things that live in capability.c */ /* things that live in capability.c */
extern struct security_operations default_security_ops;
extern void security_fixup_ops(struct security_operations *ops); extern void 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",
};
static inline int verify(struct security_operations *ops) static inline int verify(struct security_operations *ops)
{ {
...@@ -63,6 +65,11 @@ int __init security_init(void) ...@@ -63,6 +65,11 @@ int __init security_init(void)
return 0; return 0;
} }
void reset_security_ops(void)
{
security_ops = &default_security_ops;
}
/* Save user chosen LSM */ /* Save user chosen LSM */
static int __init choose_lsm(char *str) static int __init choose_lsm(char *str)
{ {
...@@ -203,9 +210,9 @@ int security_quota_on(struct dentry *dentry) ...@@ -203,9 +210,9 @@ int security_quota_on(struct dentry *dentry)
return security_ops->quota_on(dentry); return security_ops->quota_on(dentry);
} }
int security_syslog(int type) int security_syslog(int type, bool from_file)
{ {
return security_ops->syslog(type); return security_ops->syslog(type, from_file);
} }
int security_settime(struct timespec *ts, struct timezone *tz) int security_settime(struct timespec *ts, struct timezone *tz)
...@@ -389,42 +396,42 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -389,42 +396,42 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
EXPORT_SYMBOL(security_inode_init_security); EXPORT_SYMBOL(security_inode_init_security);
#ifdef CONFIG_SECURITY_PATH #ifdef CONFIG_SECURITY_PATH
int security_path_mknod(struct path *path, struct dentry *dentry, int mode, int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
unsigned int dev) unsigned int dev)
{ {
if (unlikely(IS_PRIVATE(path->dentry->d_inode))) if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
return 0; return 0;
return security_ops->path_mknod(path, dentry, mode, dev); return security_ops->path_mknod(dir, dentry, mode, dev);
} }
EXPORT_SYMBOL(security_path_mknod); EXPORT_SYMBOL(security_path_mknod);
int security_path_mkdir(struct path *path, struct dentry *dentry, int mode) int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
{ {
if (unlikely(IS_PRIVATE(path->dentry->d_inode))) if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
return 0; return 0;
return security_ops->path_mkdir(path, dentry, mode); return security_ops->path_mkdir(dir, dentry, mode);
} }
int security_path_rmdir(struct path *path, struct dentry *dentry) int security_path_rmdir(struct path *dir, struct dentry *dentry)
{ {
if (unlikely(IS_PRIVATE(path->dentry->d_inode))) if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
return 0; return 0;
return security_ops->path_rmdir(path, dentry); return security_ops->path_rmdir(dir, dentry);
} }
int security_path_unlink(struct path *path, struct dentry *dentry) int security_path_unlink(struct path *dir, struct dentry *dentry)
{ {
if (unlikely(IS_PRIVATE(path->dentry->d_inode))) if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
return 0; return 0;
return security_ops->path_unlink(path, dentry); return security_ops->path_unlink(dir, dentry);
} }
int security_path_symlink(struct path *path, struct dentry *dentry, int security_path_symlink(struct path *dir, struct dentry *dentry,
const char *old_name) const char *old_name)
{ {
if (unlikely(IS_PRIVATE(path->dentry->d_inode))) if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
return 0; return 0;
return security_ops->path_symlink(path, dentry, old_name); return security_ops->path_symlink(dir, dentry, old_name);
} }
int security_path_link(struct dentry *old_dentry, struct path *new_dir, int security_path_link(struct dentry *old_dentry, struct path *new_dir,
...@@ -630,14 +637,14 @@ int security_inode_killpriv(struct dentry *dentry) ...@@ -630,14 +637,14 @@ int security_inode_killpriv(struct dentry *dentry)
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc) int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{ {
if (unlikely(IS_PRIVATE(inode))) if (unlikely(IS_PRIVATE(inode)))
return 0; return -EOPNOTSUPP;
return security_ops->inode_getsecurity(inode, name, buffer, alloc); 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) int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
{ {
if (unlikely(IS_PRIVATE(inode))) if (unlikely(IS_PRIVATE(inode)))
return 0; return -EOPNOTSUPP;
return security_ops->inode_setsecurity(inode, name, value, size, flags); return security_ops->inode_setsecurity(inode, name, value, size, flags);
} }
......
...@@ -489,17 +489,14 @@ void avc_audit(u32 ssid, u32 tsid, ...@@ -489,17 +489,14 @@ void avc_audit(u32 ssid, u32 tsid,
struct common_audit_data stack_data; struct common_audit_data stack_data;
u32 denied, audited; u32 denied, audited;
denied = requested & ~avd->allowed; denied = requested & ~avd->allowed;
if (denied) { if (denied)
audited = denied; audited = denied & avd->auditdeny;
if (!(audited & avd->auditdeny)) else if (result)
return;
} else if (result) {
audited = denied = requested; audited = denied = requested;
} else { else
audited = requested; audited = requested & avd->auditallow;
if (!(audited & avd->auditallow)) if (!audited)
return; return;
}
if (!a) { if (!a) {
a = &stack_data; a = &stack_data;
memset(a, 0, sizeof(*a)); memset(a, 0, sizeof(*a));
...@@ -746,9 +743,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, ...@@ -746,9 +743,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
else else
avd = &avd_entry; avd = &avd_entry;
rc = security_compute_av(ssid, tsid, tclass, requested, avd); security_compute_av(ssid, tsid, tclass, avd);
if (rc)
goto out;
rcu_read_lock(); rcu_read_lock();
node = avc_insert(ssid, tsid, tclass, avd); node = avc_insert(ssid, tsid, tclass, avd);
} else { } else {
...@@ -770,7 +765,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, ...@@ -770,7 +765,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
} }
rcu_read_unlock(); rcu_read_unlock();
out:
return rc; return rc;
} }
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
#include <linux/selinux.h> #include <linux/selinux.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/posix-timers.h> #include <linux/posix-timers.h>
#include <linux/syslog.h>
#include "avc.h" #include "avc.h"
#include "objsec.h" #include "objsec.h"
...@@ -125,13 +126,6 @@ __setup("selinux=", selinux_enabled_setup); ...@@ -125,13 +126,6 @@ __setup("selinux=", selinux_enabled_setup);
int selinux_enabled = 1; int selinux_enabled = 1;
#endif #endif
/*
* Minimal support for a secondary security module,
* just to allow the use of the capability module.
*/
static struct security_operations *secondary_ops;
/* Lists of inode and superblock security structures initialized /* Lists of inode and superblock security structures initialized
before the policy was loaded. */ before the policy was loaded. */
static LIST_HEAD(superblock_security_head); static LIST_HEAD(superblock_security_head);
...@@ -2049,29 +2043,30 @@ static int selinux_quota_on(struct dentry *dentry) ...@@ -2049,29 +2043,30 @@ static int selinux_quota_on(struct dentry *dentry)
return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
} }
static int selinux_syslog(int type) static int selinux_syslog(int type, bool from_file)
{ {
int rc; int rc;
rc = cap_syslog(type); rc = cap_syslog(type, from_file);
if (rc) if (rc)
return rc; return rc;
switch (type) { switch (type) {
case 3: /* Read last kernel messages */ case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case 10: /* Return size of the log buffer */ case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
rc = task_has_system(current, SYSTEM__SYSLOG_READ); rc = task_has_system(current, SYSTEM__SYSLOG_READ);
break; break;
case 6: /* Disable logging to console */ case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case 7: /* Enable logging to console */ case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
case 8: /* Set level of messages printed to console */ /* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
break; break;
case 0: /* Close log */ case SYSLOG_ACTION_CLOSE: /* Close log */
case 1: /* Open log */ case SYSLOG_ACTION_OPEN: /* Open log */
case 2: /* Read from log */ case SYSLOG_ACTION_READ: /* Read from log */
case 4: /* Read/clear last kernel messages */ case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
case 5: /* Clear ring buffer */ case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
default: default:
rc = task_has_system(current, SYSTEM__SYSLOG_MOD); rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
break; break;
...@@ -3334,7 +3329,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) ...@@ -3334,7 +3329,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
if (ret == 0) if (ret == 0)
tsec->create_sid = isec->sid; tsec->create_sid = isec->sid;
return 0; return ret;
} }
static int selinux_kernel_module_request(char *kmod_name) static int selinux_kernel_module_request(char *kmod_name)
...@@ -5672,9 +5667,6 @@ static __init int selinux_init(void) ...@@ -5672,9 +5667,6 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
avc_init(); avc_init();
secondary_ops = security_ops;
if (!secondary_ops)
panic("SELinux: No initial security operations\n");
if (register_security(&selinux_ops)) if (register_security(&selinux_ops))
panic("SELinux: Unable to register with kernel.\n"); panic("SELinux: Unable to register with kernel.\n");
...@@ -5835,8 +5827,7 @@ int selinux_disable(void) ...@@ -5835,8 +5827,7 @@ int selinux_disable(void)
selinux_disabled = 1; selinux_disabled = 1;
selinux_enabled = 0; selinux_enabled = 0;
/* Reset security_ops to the secondary module, dummy or capability. */ reset_security_ops();
security_ops = secondary_ops;
/* Try to destroy the avc node cache */ /* Try to destroy the avc node cache */
avc_disable(); avc_disable();
......
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
struct netlbl_lsm_secattr; struct netlbl_lsm_secattr;
extern int selinux_enabled; extern int selinux_enabled;
extern int selinux_mls_enabled;
/* Policy capabilities */ /* Policy capabilities */
enum { enum {
...@@ -80,6 +79,8 @@ extern int selinux_policycap_openperm; ...@@ -80,6 +79,8 @@ extern int selinux_policycap_openperm;
/* limitation of boundary depth */ /* limitation of boundary depth */
#define POLICYDB_BOUNDS_MAXDEPTH 4 #define POLICYDB_BOUNDS_MAXDEPTH 4
int security_mls_enabled(void);
int security_load_policy(void *data, size_t len); int security_load_policy(void *data, size_t len);
int security_policycap_supported(unsigned int req_cap); int security_policycap_supported(unsigned int req_cap);
...@@ -96,13 +97,11 @@ struct av_decision { ...@@ -96,13 +97,11 @@ struct av_decision {
/* definitions of av_decision.flags */ /* definitions of av_decision.flags */
#define AVD_FLAGS_PERMISSIVE 0x0001 #define AVD_FLAGS_PERMISSIVE 0x0001
int security_compute_av(u32 ssid, u32 tsid, void security_compute_av(u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, struct av_decision *avd);
struct av_decision *avd);
int security_compute_av_user(u32 ssid, u32 tsid, void security_compute_av_user(u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, struct av_decision *avd);
struct av_decision *avd);
int security_transition_sid(u32 ssid, u32 tsid, int security_transition_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid); u16 tclass, u32 *out_sid);
......
...@@ -282,7 +282,8 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf, ...@@ -282,7 +282,8 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled); length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
security_mls_enabled());
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
} }
...@@ -494,7 +495,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) ...@@ -494,7 +495,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
char *scon, *tcon; char *scon, *tcon;
u32 ssid, tsid; u32 ssid, tsid;
u16 tclass; u16 tclass;
u32 req;
struct av_decision avd; struct av_decision avd;
ssize_t length; ssize_t length;
...@@ -512,7 +512,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) ...@@ -512,7 +512,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
goto out; goto out;
length = -EINVAL; length = -EINVAL;
if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2; goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid); length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
...@@ -522,9 +522,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) ...@@ -522,9 +522,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (length < 0) if (length < 0)
goto out2; goto out2;
length = security_compute_av_user(ssid, tsid, tclass, req, &avd); security_compute_av_user(ssid, tsid, tclass, &avd);
if (length < 0)
goto out2;
length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
"%x %x %x %x %u %x", "%x %x %x %x %u %x",
...@@ -979,6 +977,8 @@ static int sel_make_bools(void) ...@@ -979,6 +977,8 @@ static int sel_make_bools(void)
u32 sid; u32 sid;
/* remove any existing files */ /* remove any existing files */
for (i = 0; i < bool_num; i++)
kfree(bool_pending_names[i]);
kfree(bool_pending_names); kfree(bool_pending_names);
kfree(bool_pending_values); kfree(bool_pending_values);
bool_pending_names = NULL; bool_pending_names = NULL;
......
...@@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src) ...@@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src)
{ {
int rc; int rc;
if (!selinux_mls_enabled)
return 0;
dst->range.level[0].sens = src->range.level[0].sens; dst->range.level[0].sens = src->range.level[0].sens;
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
if (rc) if (rc)
...@@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) ...@@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src)
{ {
int rc; int rc;
if (!selinux_mls_enabled)
return 0;
dst->range.level[0].sens = src->range.level[0].sens; dst->range.level[0].sens = src->range.level[0].sens;
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
if (rc) if (rc)
...@@ -82,9 +76,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) ...@@ -82,9 +76,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src)
static inline int mls_context_cmp(struct context *c1, struct context *c2) static inline int mls_context_cmp(struct context *c1, struct context *c2)
{ {
if (!selinux_mls_enabled)
return 1;
return ((c1->range.level[0].sens == c2->range.level[0].sens) && return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
(c1->range.level[1].sens == c2->range.level[1].sens) && (c1->range.level[1].sens == c2->range.level[1].sens) &&
...@@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2) ...@@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2)
static inline void mls_context_destroy(struct context *c) static inline void mls_context_destroy(struct context *c)
{ {
if (!selinux_mls_enabled)
return;
ebitmap_destroy(&c->range.level[0].cat); ebitmap_destroy(&c->range.level[0].cat);
ebitmap_destroy(&c->range.level[1].cat); ebitmap_destroy(&c->range.level[1].cat);
mls_context_init(c); mls_context_init(c);
......
...@@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context) ...@@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context)
struct ebitmap *e; struct ebitmap *e;
struct ebitmap_node *node; struct ebitmap_node *node;
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return 0; return 0;
len = 1; /* for the beginning ":" */ len = 1; /* for the beginning ":" */
...@@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context, ...@@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context,
struct ebitmap *e; struct ebitmap *e;
struct ebitmap_node *node; struct ebitmap_node *node;
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return; return;
scontextp = *scontext; scontextp = *scontext;
...@@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) ...@@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
{ {
struct user_datum *usrdatum; struct user_datum *usrdatum;
if (!selinux_mls_enabled) if (!p->mls_enabled)
return 1; return 1;
if (!mls_range_isvalid(p, &c->range)) if (!mls_range_isvalid(p, &c->range))
...@@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol, ...@@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol,
struct cat_datum *catdatum, *rngdatum; struct cat_datum *catdatum, *rngdatum;
int l, rc = -EINVAL; int l, rc = -EINVAL;
if (!selinux_mls_enabled) { if (!pol->mls_enabled) {
if (def_sid != SECSID_NULL && oldc) if (def_sid != SECSID_NULL && oldc)
*scontext += strlen(*scontext)+1; *scontext += strlen(*scontext)+1;
return 0; return 0;
...@@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) ...@@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
char *tmpstr, *freestr; char *tmpstr, *freestr;
int rc; int rc;
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return -EINVAL; return -EINVAL;
/* we need freestr because mls_context_to_sid will change /* we need freestr because mls_context_to_sid will change
...@@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) ...@@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
/* /*
* Copies the MLS range `range' into `context'. * Copies the MLS range `range' into `context'.
*/ */
static inline int mls_range_set(struct context *context, int mls_range_set(struct context *context,
struct mls_range *range) struct mls_range *range)
{ {
int l, rc = 0; int l, rc = 0;
...@@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context, ...@@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context,
int mls_setup_user_range(struct context *fromcon, struct user_datum *user, int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
struct context *usercon) struct context *usercon)
{ {
if (selinux_mls_enabled) { if (policydb.mls_enabled) {
struct mls_level *fromcon_sen = &(fromcon->range.level[0]); struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
struct mls_level *fromcon_clr = &(fromcon->range.level[1]); struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
struct mls_level *user_low = &(user->range.level[0]); struct mls_level *user_low = &(user->range.level[0]);
...@@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp, ...@@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp,
struct ebitmap_node *node; struct ebitmap_node *node;
int l, i; int l, i;
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return 0; return 0;
for (l = 0; l < 2; l++) { for (l = 0; l < 2; l++) {
...@@ -513,23 +513,21 @@ int mls_compute_sid(struct context *scontext, ...@@ -513,23 +513,21 @@ int mls_compute_sid(struct context *scontext,
u32 specified, u32 specified,
struct context *newcontext) struct context *newcontext)
{ {
struct range_trans *rtr; struct range_trans rtr;
struct mls_range *r;
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return 0; return 0;
switch (specified) { switch (specified) {
case AVTAB_TRANSITION: case AVTAB_TRANSITION:
/* Look for a range transition rule. */ /* Look for a range transition rule. */
for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { rtr.source_type = scontext->type;
if (rtr->source_type == scontext->type && rtr.target_type = tcontext->type;
rtr->target_type == tcontext->type && rtr.target_class = tclass;
rtr->target_class == tclass) { r = hashtab_search(policydb.range_tr, &rtr);
/* Set the range from the rule */ if (r)
return mls_range_set(newcontext, return mls_range_set(newcontext, r);
&rtr->target_range);
}
}
/* Fallthrough */ /* Fallthrough */
case AVTAB_CHANGE: case AVTAB_CHANGE:
if (tclass == policydb.process_class) if (tclass == policydb.process_class)
...@@ -541,8 +539,8 @@ int mls_compute_sid(struct context *scontext, ...@@ -541,8 +539,8 @@ int mls_compute_sid(struct context *scontext,
case AVTAB_MEMBER: case AVTAB_MEMBER:
/* Use the process effective MLS attributes. */ /* Use the process effective MLS attributes. */
return mls_context_cpy_low(newcontext, scontext); return mls_context_cpy_low(newcontext, scontext);
default:
return -EINVAL; /* fall through */
} }
return -EINVAL; return -EINVAL;
} }
...@@ -561,7 +559,7 @@ int mls_compute_sid(struct context *scontext, ...@@ -561,7 +559,7 @@ int mls_compute_sid(struct context *scontext,
void mls_export_netlbl_lvl(struct context *context, void mls_export_netlbl_lvl(struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return; return;
secattr->attr.mls.lvl = context->range.level[0].sens - 1; secattr->attr.mls.lvl = context->range.level[0].sens - 1;
...@@ -581,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context, ...@@ -581,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context,
void mls_import_netlbl_lvl(struct context *context, void mls_import_netlbl_lvl(struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return; return;
context->range.level[0].sens = secattr->attr.mls.lvl + 1; context->range.level[0].sens = secattr->attr.mls.lvl + 1;
...@@ -603,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context, ...@@ -603,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context,
{ {
int rc; int rc;
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return 0; return 0;
rc = ebitmap_netlbl_export(&context->range.level[0].cat, rc = ebitmap_netlbl_export(&context->range.level[0].cat,
...@@ -631,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context, ...@@ -631,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context,
{ {
int rc; int rc;
if (!selinux_mls_enabled) if (!policydb.mls_enabled)
return 0; return 0;
rc = ebitmap_netlbl_import(&context->range.level[0].cat, rc = ebitmap_netlbl_import(&context->range.level[0].cat,
......
...@@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p, ...@@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p,
int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); int mls_from_string(char *str, struct context *context, gfp_t gfp_mask);
int mls_range_set(struct context *context, struct mls_range *range);
int mls_convert_context(struct policydb *oldp, int mls_convert_context(struct policydb *oldp,
struct policydb *newp, struct policydb *newp,
struct context *context); struct context *context);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define _SS_MLS_TYPES_H_ #define _SS_MLS_TYPES_H_
#include "security.h" #include "security.h"
#include "ebitmap.h"
struct mls_level { struct mls_level {
u32 sens; /* sensitivity */ u32 sens; /* sensitivity */
...@@ -27,18 +28,12 @@ struct mls_range { ...@@ -27,18 +28,12 @@ struct mls_range {
static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
{ {
if (!selinux_mls_enabled)
return 1;
return ((l1->sens == l2->sens) && return ((l1->sens == l2->sens) &&
ebitmap_cmp(&l1->cat, &l2->cat)); ebitmap_cmp(&l1->cat, &l2->cat));
} }
static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
{ {
if (!selinux_mls_enabled)
return 1;
return ((l1->sens >= l2->sens) && return ((l1->sens >= l2->sens) &&
ebitmap_contains(&l1->cat, &l2->cat)); ebitmap_contains(&l1->cat, &l2->cat));
} }
......
...@@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = { ...@@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = {
}; };
#endif #endif
int selinux_mls_enabled;
static unsigned int symtab_sizes[SYM_NUM] = { static unsigned int symtab_sizes[SYM_NUM] = {
2, 2,
32, 32,
...@@ -177,6 +175,21 @@ static int roles_init(struct policydb *p) ...@@ -177,6 +175,21 @@ static int roles_init(struct policydb *p)
goto out; goto out;
} }
static u32 rangetr_hash(struct hashtab *h, const void *k)
{
const struct range_trans *key = k;
return (key->source_type + (key->target_type << 3) +
(key->target_class << 5)) & (h->size - 1);
}
static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
{
const struct range_trans *key1 = k1, *key2 = k2;
return (key1->source_type != key2->source_type ||
key1->target_type != key2->target_type ||
key1->target_class != key2->target_class);
}
/* /*
* Initialize a policy database structure. * Initialize a policy database structure.
*/ */
...@@ -204,6 +217,10 @@ static int policydb_init(struct policydb *p) ...@@ -204,6 +217,10 @@ static int policydb_init(struct policydb *p)
if (rc) if (rc)
goto out_free_symtab; goto out_free_symtab;
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
if (!p->range_tr)
goto out_free_symtab;
ebitmap_init(&p->policycaps); ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map); ebitmap_init(&p->permissive_map);
...@@ -408,6 +425,20 @@ static void symtab_hash_eval(struct symtab *s) ...@@ -408,6 +425,20 @@ static void symtab_hash_eval(struct symtab *s)
info.slots_used, h->size, info.max_chain_len); info.slots_used, h->size, info.max_chain_len);
} }
} }
static void rangetr_hash_eval(struct hashtab *h)
{
struct hashtab_info info;
hashtab_stat(h, &info);
printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, "
"longest chain length %d\n", h->nel,
info.slots_used, h->size, info.max_chain_len);
}
#else
static inline void rangetr_hash_eval(struct hashtab *h)
{
}
#endif #endif
/* /*
...@@ -422,7 +453,7 @@ static int policydb_index_others(struct policydb *p) ...@@ -422,7 +453,7 @@ static int policydb_index_others(struct policydb *p)
printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
if (selinux_mls_enabled) if (p->mls_enabled)
printk(", %d sens, %d cats", p->p_levels.nprim, printk(", %d sens, %d cats", p->p_levels.nprim,
p->p_cats.nprim); p->p_cats.nprim);
printk("\n"); printk("\n");
...@@ -612,6 +643,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = ...@@ -612,6 +643,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
cat_destroy, cat_destroy,
}; };
static int range_tr_destroy(void *key, void *datum, void *p)
{
struct mls_range *rt = datum;
kfree(key);
ebitmap_destroy(&rt->level[0].cat);
ebitmap_destroy(&rt->level[1].cat);
kfree(datum);
cond_resched();
return 0;
}
static void ocontext_destroy(struct ocontext *c, int i) static void ocontext_destroy(struct ocontext *c, int i)
{ {
context_destroy(&c->context[0]); context_destroy(&c->context[0]);
...@@ -632,7 +674,6 @@ void policydb_destroy(struct policydb *p) ...@@ -632,7 +674,6 @@ void policydb_destroy(struct policydb *p)
int i; int i;
struct role_allow *ra, *lra = NULL; struct role_allow *ra, *lra = NULL;
struct role_trans *tr, *ltr = NULL; struct role_trans *tr, *ltr = NULL;
struct range_trans *rt, *lrt = NULL;
for (i = 0; i < SYM_NUM; i++) { for (i = 0; i < SYM_NUM; i++) {
cond_resched(); cond_resched();
...@@ -693,20 +734,8 @@ void policydb_destroy(struct policydb *p) ...@@ -693,20 +734,8 @@ void policydb_destroy(struct policydb *p)
} }
kfree(lra); kfree(lra);
for (rt = p->range_tr; rt; rt = rt->next) { hashtab_map(p->range_tr, range_tr_destroy, NULL);
cond_resched(); hashtab_destroy(p->range_tr);
if (lrt) {
ebitmap_destroy(&lrt->target_range.level[0].cat);
ebitmap_destroy(&lrt->target_range.level[1].cat);
kfree(lrt);
}
lrt = rt;
}
if (lrt) {
ebitmap_destroy(&lrt->target_range.level[0].cat);
ebitmap_destroy(&lrt->target_range.level[1].cat);
kfree(lrt);
}
if (p->type_attr_map) { if (p->type_attr_map) {
for (i = 0; i < p->p_types.nprim; i++) for (i = 0; i < p->p_types.nprim; i++)
...@@ -1686,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1686,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp)
int i, j, rc; int i, j, rc;
__le32 buf[4]; __le32 buf[4];
u32 nodebuf[8]; u32 nodebuf[8];
u32 len, len2, config, nprim, nel, nel2; u32 len, len2, nprim, nel, nel2;
char *policydb_str; char *policydb_str;
struct policydb_compat_info *info; struct policydb_compat_info *info;
struct range_trans *rt, *lrt; struct range_trans *rt;
struct mls_range *r;
config = 0;
rc = policydb_init(p); rc = policydb_init(p);
if (rc) if (rc)
...@@ -1740,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1740,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp)
kfree(policydb_str); kfree(policydb_str);
policydb_str = NULL; policydb_str = NULL;
/* Read the version, config, and table sizes. */ /* Read the version and table sizes. */
rc = next_entry(buf, fp, sizeof(u32)*4); rc = next_entry(buf, fp, sizeof(u32)*4);
if (rc < 0) if (rc < 0)
goto bad; goto bad;
...@@ -1755,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1755,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp)
} }
if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
if (ss_initialized && !selinux_mls_enabled) { p->mls_enabled = 1;
printk(KERN_ERR "SELinux: Cannot switch between non-MLS"
" and MLS policies\n");
goto bad;
}
selinux_mls_enabled = 1;
config |= POLICYDB_CONFIG_MLS;
if (p->policyvers < POLICYDB_VERSION_MLS) { if (p->policyvers < POLICYDB_VERSION_MLS) {
printk(KERN_ERR "SELinux: security policydb version %d " printk(KERN_ERR "SELinux: security policydb version %d "
...@@ -1769,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1769,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp)
p->policyvers); p->policyvers);
goto bad; goto bad;
} }
} else {
if (ss_initialized && selinux_mls_enabled) {
printk(KERN_ERR "SELinux: Cannot switch between MLS and"
" non-MLS policies\n");
goto bad;
}
} }
p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
...@@ -2122,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -2122,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp)
if (rc < 0) if (rc < 0)
goto bad; goto bad;
nel = le32_to_cpu(buf[0]); nel = le32_to_cpu(buf[0]);
lrt = NULL;
for (i = 0; i < nel; i++) { for (i = 0; i < nel; i++) {
rt = kzalloc(sizeof(*rt), GFP_KERNEL); rt = kzalloc(sizeof(*rt), GFP_KERNEL);
if (!rt) { if (!rt) {
rc = -ENOMEM; rc = -ENOMEM;
goto bad; goto bad;
} }
if (lrt)
lrt->next = rt;
else
p->range_tr = rt;
rc = next_entry(buf, fp, (sizeof(u32) * 2)); rc = next_entry(buf, fp, (sizeof(u32) * 2));
if (rc < 0) if (rc < 0) {
kfree(rt);
goto bad; goto bad;
}
rt->source_type = le32_to_cpu(buf[0]); rt->source_type = le32_to_cpu(buf[0]);
rt->target_type = le32_to_cpu(buf[1]); rt->target_type = le32_to_cpu(buf[1]);
if (new_rangetr) { if (new_rangetr) {
rc = next_entry(buf, fp, sizeof(u32)); rc = next_entry(buf, fp, sizeof(u32));
if (rc < 0) if (rc < 0) {
kfree(rt);
goto bad; goto bad;
}
rt->target_class = le32_to_cpu(buf[0]); rt->target_class = le32_to_cpu(buf[0]);
} else } else
rt->target_class = p->process_class; rt->target_class = p->process_class;
if (!policydb_type_isvalid(p, rt->source_type) || if (!policydb_type_isvalid(p, rt->source_type) ||
!policydb_type_isvalid(p, rt->target_type) || !policydb_type_isvalid(p, rt->target_type) ||
!policydb_class_isvalid(p, rt->target_class)) { !policydb_class_isvalid(p, rt->target_class)) {
kfree(rt);
rc = -EINVAL; rc = -EINVAL;
goto bad; goto bad;
} }
rc = mls_read_range_helper(&rt->target_range, fp); r = kzalloc(sizeof(*r), GFP_KERNEL);
if (rc) if (!r) {
kfree(rt);
rc = -ENOMEM;
goto bad; goto bad;
if (!mls_range_isvalid(p, &rt->target_range)) { }
rc = mls_read_range_helper(r, fp);
if (rc) {
kfree(rt);
kfree(r);
goto bad;
}
if (!mls_range_isvalid(p, r)) {
printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); printk(KERN_WARNING "SELinux: rangetrans: invalid range\n");
kfree(rt);
kfree(r);
goto bad;
}
rc = hashtab_insert(p->range_tr, rt, r);
if (rc) {
kfree(rt);
kfree(r);
goto bad; goto bad;
} }
lrt = rt;
} }
rangetr_hash_eval(p->range_tr);
} }
p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL);
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "symtab.h" #include "symtab.h"
#include "avtab.h" #include "avtab.h"
#include "sidtab.h" #include "sidtab.h"
#include "ebitmap.h"
#include "mls_types.h"
#include "context.h" #include "context.h"
#include "constraint.h" #include "constraint.h"
...@@ -113,8 +115,6 @@ struct range_trans { ...@@ -113,8 +115,6 @@ struct range_trans {
u32 source_type; u32 source_type;
u32 target_type; u32 target_type;
u32 target_class; u32 target_class;
struct mls_range target_range;
struct range_trans *next;
}; };
/* Boolean data type */ /* Boolean data type */
...@@ -187,6 +187,8 @@ struct genfs { ...@@ -187,6 +187,8 @@ struct genfs {
/* The policy database */ /* The policy database */
struct policydb { struct policydb {
int mls_enabled;
/* symbol tables */ /* symbol tables */
struct symtab symtab[SYM_NUM]; struct symtab symtab[SYM_NUM];
#define p_commons symtab[SYM_COMMONS] #define p_commons symtab[SYM_COMMONS]
...@@ -240,8 +242,8 @@ struct policydb { ...@@ -240,8 +242,8 @@ struct policydb {
fixed labeling behavior. */ fixed labeling behavior. */
struct genfs *genfs; struct genfs *genfs;
/* range transitions */ /* range transitions table (range_trans_key -> mls_range) */
struct range_trans *range_tr; struct hashtab *range_tr;
/* type -> attribute reverse mapping */ /* type -> attribute reverse mapping */
struct ebitmap *type_attr_map; struct ebitmap *type_attr_map;
......
This diff is collapsed.
...@@ -157,12 +157,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp) ...@@ -157,12 +157,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
* *
* Returns 0 on success, error code otherwise. * Returns 0 on success, error code otherwise.
*/ */
static int smack_syslog(int type) static int smack_syslog(int type, bool from_file)
{ {
int rc; int rc;
char *sp = current_security(); char *sp = current_security();
rc = cap_syslog(type); rc = cap_syslog(type, from_file);
if (rc != 0) if (rc != 0)
return rc; return rc;
......
obj-y = common.o realpath.o tomoyo.o domain.o file.o obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* security/tomoyo/gc.c
*
* Implementation of the Domain-Based Mandatory Access Control.
*
* Copyright (C) 2005-2010 NTT DATA CORPORATION
*
*/
#include "common.h"
#include <linux/kthread.h>
enum tomoyo_gc_id {
TOMOYO_ID_DOMAIN_INITIALIZER,
TOMOYO_ID_DOMAIN_KEEPER,
TOMOYO_ID_ALIAS,
TOMOYO_ID_GLOBALLY_READABLE,
TOMOYO_ID_PATTERN,
TOMOYO_ID_NO_REWRITE,
TOMOYO_ID_MANAGER,
TOMOYO_ID_NAME,
TOMOYO_ID_ACL,
TOMOYO_ID_DOMAIN
};
struct tomoyo_gc_entry {
struct list_head list;
int type;
void *element;
};
static LIST_HEAD(tomoyo_gc_queue);
static DEFINE_MUTEX(tomoyo_gc_mutex);
/* Caller holds tomoyo_policy_lock mutex. */
static bool tomoyo_add_to_gc(const int type, void *element)
{
struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return false;
entry->type = type;
entry->element = element;
list_add(&entry->list, &tomoyo_gc_queue);
return true;
}
static void tomoyo_del_allow_read
(struct tomoyo_globally_readable_file_entry *ptr)
{
tomoyo_put_name(ptr->filename);
}
static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr)
{
tomoyo_put_name(ptr->pattern);
}
static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr)
{
tomoyo_put_name(ptr->pattern);
}
static void tomoyo_del_domain_initializer
(struct tomoyo_domain_initializer_entry *ptr)
{
tomoyo_put_name(ptr->domainname);
tomoyo_put_name(ptr->program);
}
static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr)
{
tomoyo_put_name(ptr->domainname);
tomoyo_put_name(ptr->program);
}
static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr)
{
tomoyo_put_name(ptr->original_name);
tomoyo_put_name(ptr->aliased_name);
}
static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr)
{
tomoyo_put_name(ptr->manager);
}
static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
{
switch (acl->type) {
case TOMOYO_TYPE_PATH_ACL:
{
struct tomoyo_path_acl *entry
= container_of(acl, typeof(*entry), head);
tomoyo_put_name(entry->filename);
}
break;
case TOMOYO_TYPE_PATH2_ACL:
{
struct tomoyo_path2_acl *entry
= container_of(acl, typeof(*entry), head);
tomoyo_put_name(entry->filename1);
tomoyo_put_name(entry->filename2);
}
break;
default:
printk(KERN_WARNING "Unknown type\n");
break;
}
}
static bool tomoyo_del_domain(struct tomoyo_domain_info *domain)
{
struct tomoyo_acl_info *acl;
struct tomoyo_acl_info *tmp;
/*
* Since we don't protect whole execve() operation using SRCU,
* we need to recheck domain->users at this point.
*
* (1) Reader starts SRCU section upon execve().
* (2) Reader traverses tomoyo_domain_list and finds this domain.
* (3) Writer marks this domain as deleted.
* (4) Garbage collector removes this domain from tomoyo_domain_list
* because this domain is marked as deleted and used by nobody.
* (5) Reader saves reference to this domain into
* "struct linux_binprm"->cred->security .
* (6) Reader finishes SRCU section, although execve() operation has
* not finished yet.
* (7) Garbage collector waits for SRCU synchronization.
* (8) Garbage collector kfree() this domain because this domain is
* used by nobody.
* (9) Reader finishes execve() operation and restores this domain from
* "struct linux_binprm"->cred->security.
*
* By updating domain->users at (5), we can solve this race problem
* by rechecking domain->users at (8).
*/
if (atomic_read(&domain->users))
return false;
list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
tomoyo_del_acl(acl);
tomoyo_memory_free(acl);
}
tomoyo_put_name(domain->domainname);
return true;
}
static void tomoyo_del_name(const struct tomoyo_name_entry *ptr)
{
}
static void tomoyo_collect_entry(void)
{
mutex_lock(&tomoyo_policy_lock);
{
struct tomoyo_globally_readable_file_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list,
list) {
if (!ptr->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr))
list_del_rcu(&ptr->list);
else
break;
}
}
{
struct tomoyo_pattern_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
if (!ptr->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr))
list_del_rcu(&ptr->list);
else
break;
}
}
{
struct tomoyo_no_rewrite_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) {
if (!ptr->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr))
list_del_rcu(&ptr->list);
else
break;
}
}
{
struct tomoyo_domain_initializer_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list,
list) {
if (!ptr->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr))
list_del_rcu(&ptr->list);
else
break;
}
}
{
struct tomoyo_domain_keeper_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
if (!ptr->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr))
list_del_rcu(&ptr->list);
else
break;
}
}
{
struct tomoyo_alias_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
if (!ptr->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr))
list_del_rcu(&ptr->list);
else
break;
}
}
{
struct tomoyo_policy_manager_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list,
list) {
if (!ptr->is_deleted)
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr))
list_del_rcu(&ptr->list);
else
break;
}
}
{
struct tomoyo_domain_info *domain;
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
struct tomoyo_acl_info *acl;
list_for_each_entry_rcu(acl, &domain->acl_info_list,
list) {
switch (acl->type) {
case TOMOYO_TYPE_PATH_ACL:
if (container_of(acl,
struct tomoyo_path_acl,
head)->perm ||
container_of(acl,
struct tomoyo_path_acl,
head)->perm_high)
continue;
break;
case TOMOYO_TYPE_PATH2_ACL:
if (container_of(acl,
struct tomoyo_path2_acl,
head)->perm)
continue;
break;
default:
continue;
}
if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl))
list_del_rcu(&acl->list);
else
break;
}
if (!domain->is_deleted || atomic_read(&domain->users))
continue;
/*
* Nobody is referring this domain. But somebody may
* refer this domain after successful execve().
* We recheck domain->users after SRCU synchronization.
*/
if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain))
list_del_rcu(&domain->list);
else
break;
}
}
mutex_unlock(&tomoyo_policy_lock);
mutex_lock(&tomoyo_name_list_lock);
{
int i;
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
struct tomoyo_name_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_name_list[i],
list) {
if (atomic_read(&ptr->users))
continue;
if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr))
list_del_rcu(&ptr->list);
else {
i = TOMOYO_MAX_HASH;
break;
}
}
}
}
mutex_unlock(&tomoyo_name_list_lock);
}
static void tomoyo_kfree_entry(void)
{
struct tomoyo_gc_entry *p;
struct tomoyo_gc_entry *tmp;
list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
switch (p->type) {
case TOMOYO_ID_DOMAIN_INITIALIZER:
tomoyo_del_domain_initializer(p->element);
break;
case TOMOYO_ID_DOMAIN_KEEPER:
tomoyo_del_domain_keeper(p->element);
break;
case TOMOYO_ID_ALIAS:
tomoyo_del_alias(p->element);
break;
case TOMOYO_ID_GLOBALLY_READABLE:
tomoyo_del_allow_read(p->element);
break;
case TOMOYO_ID_PATTERN:
tomoyo_del_file_pattern(p->element);
break;
case TOMOYO_ID_NO_REWRITE:
tomoyo_del_no_rewrite(p->element);
break;
case TOMOYO_ID_MANAGER:
tomoyo_del_manager(p->element);
break;
case TOMOYO_ID_NAME:
tomoyo_del_name(p->element);
break;
case TOMOYO_ID_ACL:
tomoyo_del_acl(p->element);
break;
case TOMOYO_ID_DOMAIN:
if (!tomoyo_del_domain(p->element))
continue;
break;
default:
printk(KERN_WARNING "Unknown type\n");
break;
}
tomoyo_memory_free(p->element);
list_del(&p->list);
kfree(p);
}
}
static int tomoyo_gc_thread(void *unused)
{
daemonize("GC for TOMOYO");
if (mutex_trylock(&tomoyo_gc_mutex)) {
int i;
for (i = 0; i < 10; i++) {
tomoyo_collect_entry();
if (list_empty(&tomoyo_gc_queue))
break;
synchronize_srcu(&tomoyo_ss);
tomoyo_kfree_entry();
}
mutex_unlock(&tomoyo_gc_mutex);
}
do_exit(0);
}
void tomoyo_run_gc(void)
{
struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
"GC for TOMOYO");
if (!IS_ERR(task))
wake_up_process(task);
}
This diff is collapsed.
/*
* security/tomoyo/realpath.h
*
* Get the canonicalized absolute pathnames. The basis for TOMOYO.
*
* Copyright (C) 2005-2009 NTT DATA CORPORATION
*
* Version: 2.2.0 2009/04/01
*
*/
#ifndef _SECURITY_TOMOYO_REALPATH_H
#define _SECURITY_TOMOYO_REALPATH_H
struct path;
struct tomoyo_path_info;
struct tomoyo_io_buffer;
/* Convert binary string to ascii string. */
int tomoyo_encode(char *buffer, int buflen, const char *str);
/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
int tomoyo_realpath_from_path2(struct path *path, char *newname,
int newname_len);
/*
* Returns realpath(3) of the given pathname but ignores chroot'ed root.
* These functions use tomoyo_alloc(), so the caller must call tomoyo_free()
* if these functions didn't return NULL.
*/
char *tomoyo_realpath(const char *pathname);
/*
* Same with tomoyo_realpath() except that it doesn't follow the final symlink.
*/
char *tomoyo_realpath_nofollow(const char *pathname);
/* Same with tomoyo_realpath() except that the pathname is already solved. */
char *tomoyo_realpath_from_path(struct path *path);
/*
* Allocate memory for ACL entry.
* The RAM is chunked, so NEVER try to kfree() the returned pointer.
*/
void *tomoyo_alloc_element(const unsigned int size);
/*
* Keep the given name on the RAM.
* The RAM is shared, so NEVER try to modify or kfree() the returned name.
*/
const struct tomoyo_path_info *tomoyo_save_name(const char *name);
/* Allocate memory for temporary use (e.g. permission checks). */
void *tomoyo_alloc(const size_t size);
/* Free memory allocated by tomoyo_alloc(). */
void tomoyo_free(const void *p);
/* Check for memory usage. */
int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
/* Set memory quota. */
int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
/* Initialize realpath related code. */
void __init tomoyo_realpath_init(void);
#endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
#include <linux/security.h> #include <linux/security.h>
#include "common.h" #include "common.h"
#include "tomoyo.h"
#include "realpath.h"
static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
{ {
...@@ -23,21 +21,23 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) ...@@ -23,21 +21,23 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp) gfp_t gfp)
{ {
/* struct tomoyo_domain_info *domain = old->security;
* Since "struct tomoyo_domain_info *" is a sharable pointer, new->security = domain;
* we don't need to duplicate. if (domain)
*/ atomic_inc(&domain->users);
new->security = old->security;
return 0; return 0;
} }
static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) static void tomoyo_cred_transfer(struct cred *new, const struct cred *old)
{ {
/* tomoyo_cred_prepare(new, old, 0);
* Since "struct tomoyo_domain_info *" is a sharable pointer, }
* we don't need to duplicate.
*/ static void tomoyo_cred_free(struct cred *cred)
new->security = old->security; {
struct tomoyo_domain_info *domain = cred->security;
if (domain)
atomic_dec(&domain->users);
} }
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
...@@ -60,6 +60,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) ...@@ -60,6 +60,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
*/ */
if (!tomoyo_policy_loaded) if (!tomoyo_policy_loaded)
tomoyo_load_policy(bprm->filename); tomoyo_load_policy(bprm->filename);
/*
* Release reference to "struct tomoyo_domain_info" stored inside
* "bprm->cred->security". New reference to "struct tomoyo_domain_info"
* stored inside "bprm->cred->security" will be acquired later inside
* tomoyo_find_next_domain().
*/
atomic_dec(&((struct tomoyo_domain_info *)
bprm->cred->security)->users);
/* /*
* Tell tomoyo_bprm_check_security() is called for the first time of an * Tell tomoyo_bprm_check_security() is called for the first time of an
* execve operation. * execve operation.
...@@ -76,8 +84,12 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) ...@@ -76,8 +84,12 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
* Execute permission is checked against pathname passed to do_execve() * Execute permission is checked against pathname passed to do_execve()
* using current domain. * using current domain.
*/ */
if (!domain) if (!domain) {
return tomoyo_find_next_domain(bprm); const int idx = tomoyo_read_lock();
const int err = tomoyo_find_next_domain(bprm);
tomoyo_read_unlock(idx);
return err;
}
/* /*
* Read permission is checked against interpreters using next domain. * Read permission is checked against interpreters using next domain.
*/ */
...@@ -87,67 +99,56 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) ...@@ -87,67 +99,56 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
static int tomoyo_path_truncate(struct path *path, loff_t length, static int tomoyo_path_truncate(struct path *path, loff_t length,
unsigned int time_attrs) unsigned int time_attrs)
{ {
return tomoyo_check_1path_perm(tomoyo_domain(), return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path);
TOMOYO_TYPE_TRUNCATE_ACL,
path);
} }
static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry)
{ {
struct path path = { parent->mnt, dentry }; struct path path = { parent->mnt, dentry };
return tomoyo_check_1path_perm(tomoyo_domain(), return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path);
TOMOYO_TYPE_UNLINK_ACL,
&path);
} }
static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
int mode) int mode)
{ {
struct path path = { parent->mnt, dentry }; struct path path = { parent->mnt, dentry };
return tomoyo_check_1path_perm(tomoyo_domain(), return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path);
TOMOYO_TYPE_MKDIR_ACL,
&path);
} }
static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
{ {
struct path path = { parent->mnt, dentry }; struct path path = { parent->mnt, dentry };
return tomoyo_check_1path_perm(tomoyo_domain(), return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path);
TOMOYO_TYPE_RMDIR_ACL,
&path);
} }
static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry,
const char *old_name) const char *old_name)
{ {
struct path path = { parent->mnt, dentry }; struct path path = { parent->mnt, dentry };
return tomoyo_check_1path_perm(tomoyo_domain(), return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path);
TOMOYO_TYPE_SYMLINK_ACL,
&path);
} }
static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
int mode, unsigned int dev) int mode, unsigned int dev)
{ {
struct path path = { parent->mnt, dentry }; struct path path = { parent->mnt, dentry };
int type = TOMOYO_TYPE_CREATE_ACL; int type = TOMOYO_TYPE_CREATE;
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
case S_IFCHR: case S_IFCHR:
type = TOMOYO_TYPE_MKCHAR_ACL; type = TOMOYO_TYPE_MKCHAR;
break; break;
case S_IFBLK: case S_IFBLK:
type = TOMOYO_TYPE_MKBLOCK_ACL; type = TOMOYO_TYPE_MKBLOCK;
break; break;
case S_IFIFO: case S_IFIFO:
type = TOMOYO_TYPE_MKFIFO_ACL; type = TOMOYO_TYPE_MKFIFO;
break; break;
case S_IFSOCK: case S_IFSOCK:
type = TOMOYO_TYPE_MKSOCK_ACL; type = TOMOYO_TYPE_MKSOCK;
break; break;
} }
return tomoyo_check_1path_perm(tomoyo_domain(), return tomoyo_path_perm(type, &path);
type, &path);
} }
static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
...@@ -155,9 +156,7 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, ...@@ -155,9 +156,7 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
{ {
struct path path1 = { new_dir->mnt, old_dentry }; struct path path1 = { new_dir->mnt, old_dentry };
struct path path2 = { new_dir->mnt, new_dentry }; struct path path2 = { new_dir->mnt, new_dentry };
return tomoyo_check_2path_perm(tomoyo_domain(), return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2);
TOMOYO_TYPE_LINK_ACL,
&path1, &path2);
} }
static int tomoyo_path_rename(struct path *old_parent, static int tomoyo_path_rename(struct path *old_parent,
...@@ -167,16 +166,14 @@ static int tomoyo_path_rename(struct path *old_parent, ...@@ -167,16 +166,14 @@ static int tomoyo_path_rename(struct path *old_parent,
{ {
struct path path1 = { old_parent->mnt, old_dentry }; struct path path1 = { old_parent->mnt, old_dentry };
struct path path2 = { new_parent->mnt, new_dentry }; struct path path2 = { new_parent->mnt, new_dentry };
return tomoyo_check_2path_perm(tomoyo_domain(), return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2);
TOMOYO_TYPE_RENAME_ACL,
&path1, &path2);
} }
static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
return tomoyo_check_rewrite_permission(tomoyo_domain(), file); return tomoyo_check_rewrite_permission(file);
return 0; return 0;
} }
...@@ -189,6 +186,51 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) ...@@ -189,6 +186,51 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
} }
static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path);
}
static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
mode_t mode)
{
struct path path = { mnt, dentry };
return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path);
}
static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
{
int error = 0;
if (uid != (uid_t) -1)
error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path);
if (!error && gid != (gid_t) -1)
error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path);
return error;
}
static int tomoyo_path_chroot(struct path *path)
{
return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path);
}
static int tomoyo_sb_mount(char *dev_name, struct path *path,
char *type, unsigned long flags, void *data)
{
return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path);
}
static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
{
struct path path = { mnt, mnt->mnt_root };
return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path);
}
static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path)
{
return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path);
}
/* /*
* tomoyo_security_ops is a "struct security_operations" which is used for * tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO. * registering TOMOYO.
...@@ -198,6 +240,7 @@ static struct security_operations tomoyo_security_ops = { ...@@ -198,6 +240,7 @@ static struct security_operations tomoyo_security_ops = {
.cred_alloc_blank = tomoyo_cred_alloc_blank, .cred_alloc_blank = tomoyo_cred_alloc_blank,
.cred_prepare = tomoyo_cred_prepare, .cred_prepare = tomoyo_cred_prepare,
.cred_transfer = tomoyo_cred_transfer, .cred_transfer = tomoyo_cred_transfer,
.cred_free = tomoyo_cred_free,
.bprm_set_creds = tomoyo_bprm_set_creds, .bprm_set_creds = tomoyo_bprm_set_creds,
.bprm_check_security = tomoyo_bprm_check_security, .bprm_check_security = tomoyo_bprm_check_security,
.file_fcntl = tomoyo_file_fcntl, .file_fcntl = tomoyo_file_fcntl,
...@@ -210,8 +253,18 @@ static struct security_operations tomoyo_security_ops = { ...@@ -210,8 +253,18 @@ static struct security_operations tomoyo_security_ops = {
.path_mknod = tomoyo_path_mknod, .path_mknod = tomoyo_path_mknod,
.path_link = tomoyo_path_link, .path_link = tomoyo_path_link,
.path_rename = tomoyo_path_rename, .path_rename = tomoyo_path_rename,
.file_ioctl = tomoyo_file_ioctl,
.path_chmod = tomoyo_path_chmod,
.path_chown = tomoyo_path_chown,
.path_chroot = tomoyo_path_chroot,
.sb_mount = tomoyo_sb_mount,
.sb_umount = tomoyo_sb_umount,
.sb_pivotroot = tomoyo_sb_pivotroot,
}; };
/* Lock for GC. */
struct srcu_struct tomoyo_ss;
static int __init tomoyo_init(void) static int __init tomoyo_init(void)
{ {
struct cred *cred = (struct cred *) current_cred(); struct cred *cred = (struct cred *) current_cred();
...@@ -219,7 +272,8 @@ static int __init tomoyo_init(void) ...@@ -219,7 +272,8 @@ static int __init tomoyo_init(void)
if (!security_module_enable(&tomoyo_security_ops)) if (!security_module_enable(&tomoyo_security_ops))
return 0; return 0;
/* register ourselves with the security framework */ /* register ourselves with the security framework */
if (register_security(&tomoyo_security_ops)) if (register_security(&tomoyo_security_ops) ||
init_srcu_struct(&tomoyo_ss))
panic("Failure registering TOMOYO Linux"); panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n"); printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain; cred->security = &tomoyo_kernel_domain;
......
/*
* security/tomoyo/tomoyo.h
*
* Implementation of the Domain-Based Mandatory Access Control.
*
* Copyright (C) 2005-2009 NTT DATA CORPORATION
*
* Version: 2.2.0 2009/04/01
*
*/
#ifndef _SECURITY_TOMOYO_TOMOYO_H
#define _SECURITY_TOMOYO_TOMOYO_H
struct tomoyo_path_info;
struct path;
struct inode;
struct linux_binprm;
struct pt_regs;
int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
const struct tomoyo_path_info *filename);
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag);
int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
const u8 operation, struct path *path);
int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain,
const u8 operation, struct path *path1,
struct path *path2);
int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
struct file *filp);
int tomoyo_find_next_domain(struct linux_binprm *bprm);
/* Index numbers for Access Controls. */
#define TOMOYO_TYPE_SINGLE_PATH_ACL 0
#define TOMOYO_TYPE_DOUBLE_PATH_ACL 1
/* Index numbers for File Controls. */
/*
* TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set
* if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and
* TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set.
* TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or
* TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are
* automatically cleared if TYPE_READ_WRITE_ACL is cleared.
*/
#define TOMOYO_TYPE_READ_WRITE_ACL 0
#define TOMOYO_TYPE_EXECUTE_ACL 1
#define TOMOYO_TYPE_READ_ACL 2
#define TOMOYO_TYPE_WRITE_ACL 3
#define TOMOYO_TYPE_CREATE_ACL 4
#define TOMOYO_TYPE_UNLINK_ACL 5
#define TOMOYO_TYPE_MKDIR_ACL 6
#define TOMOYO_TYPE_RMDIR_ACL 7
#define TOMOYO_TYPE_MKFIFO_ACL 8
#define TOMOYO_TYPE_MKSOCK_ACL 9
#define TOMOYO_TYPE_MKBLOCK_ACL 10
#define TOMOYO_TYPE_MKCHAR_ACL 11
#define TOMOYO_TYPE_TRUNCATE_ACL 12
#define TOMOYO_TYPE_SYMLINK_ACL 13
#define TOMOYO_TYPE_REWRITE_ACL 14
#define TOMOYO_MAX_SINGLE_PATH_OPERATION 15
#define TOMOYO_TYPE_LINK_ACL 0
#define TOMOYO_TYPE_RENAME_ACL 1
#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 2
#define TOMOYO_DOMAINPOLICY 0
#define TOMOYO_EXCEPTIONPOLICY 1
#define TOMOYO_DOMAIN_STATUS 2
#define TOMOYO_PROCESS_STATUS 3
#define TOMOYO_MEMINFO 4
#define TOMOYO_SELFDOMAIN 5
#define TOMOYO_VERSION 6
#define TOMOYO_PROFILE 7
#define TOMOYO_MANAGER 8
extern struct tomoyo_domain_info tomoyo_kernel_domain;
static inline struct tomoyo_domain_info *tomoyo_domain(void)
{
return current_cred()->security;
}
static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
*task)
{
return task_cred_xxx(task, security);
}
#endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment