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: (43 commits)
  TOMOYO: Fix wrong domainname validation.
  SELINUX: add /sys/fs/selinux mount point to put selinuxfs
  CRED: Fix load_flat_shared_library() to initialise bprm correctly
  SELinux: introduce path_has_perm
  flex_array: allow 0 length elements
  flex_arrays: allow zero length flex arrays
  flex_array: flex_array_prealloc takes a number of elements, not an end
  SELinux: pass last path component in may_create
  SELinux: put name based create rules in a hashtable
  SELinux: generic hashtab entry counter
  SELinux: calculate and print hashtab stats with a generic function
  SELinux: skip filename trans rules if ttype does not match parent dir
  SELinux: rename filename_compute_type argument to *type instead of *con
  SELinux: fix comment to state filename_compute_type takes an objname not a qstr
  SMACK: smack_file_lock can use the struct path
  LSM: separate LSM_AUDIT_DATA_DENTRY from LSM_AUDIT_DATA_PATH
  LSM: split LSM_AUDIT_DATA_FS into _PATH and _INODE
  SELINUX: Make selinux cache VFS RCU walks safe
  SECURITY: Move exec_permission RCU checks into security modules
  SELinux: security_read_policy should take a size_t not ssize_t
  ...
This commit is contained in:
Linus Torvalds 2011-05-24 13:38:19 -07:00
commit b0ca118dba
39 changed files with 604 additions and 285 deletions

View file

@ -5592,10 +5592,11 @@ M: James Morris <jmorris@namei.org>
M: Eric Paris <eparis@parisplace.org> M: Eric Paris <eparis@parisplace.org>
L: selinux@tycho.nsa.gov (subscribers-only, general discussion) L: selinux@tycho.nsa.gov (subscribers-only, general discussion)
W: http://selinuxproject.org W: http://selinuxproject.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git T: git git://git.infradead.org/users/eparis/selinux.git
S: Supported S: Supported
F: include/linux/selinux* F: include/linux/selinux*
F: security/selinux/ F: security/selinux/
F: scripts/selinux/
APPARMOR SECURITY MODULE APPARMOR SECURITY MODULE
M: John Johansen <john.johansen@canonical.com> M: John Johansen <john.johansen@canonical.com>

View file

@ -820,6 +820,8 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
int res; int res;
char buf[16]; char buf[16];
memset(&bprm, 0, sizeof(bprm));
/* Create the file name */ /* Create the file name */
sprintf(buf, "/lib/lib%d.so", id); sprintf(buf, "/lib/lib%d.so", id);
@ -835,6 +837,12 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
if (!bprm.cred) if (!bprm.cred)
goto out; goto out;
/* We don't really care about recalculating credentials at this point
* as we're past the point of no return and are dealing with shared
* libraries.
*/
bprm.cred_prepared = 1;
res = prepare_binprm(&bprm); res = prepare_binprm(&bprm);
if (!IS_ERR_VALUE(res)) if (!IS_ERR_VALUE(res))

View file

@ -417,7 +417,6 @@ extern const kernel_cap_t __cap_init_eff_set;
# define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }}) # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
# define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }}) # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
# define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }})
# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
| CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \ | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
CAP_FS_MASK_B1 } }) CAP_FS_MASK_B1 } })
@ -427,11 +426,7 @@ extern const kernel_cap_t __cap_init_eff_set;
#endif /* _KERNEL_CAPABILITY_U32S != 2 */ #endif /* _KERNEL_CAPABILITY_U32S != 2 */
#define CAP_INIT_INH_SET CAP_EMPTY_SET
# define cap_clear(c) do { (c) = __cap_empty_set; } while (0) # define cap_clear(c) do { (c) = __cap_empty_set; } while (0)
# define cap_set_full(c) do { (c) = __cap_full_set; } while (0)
# define cap_set_init_eff(c) do { (c) = __cap_init_eff_set; } while (0)
#define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag)) #define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
#define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag)) #define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))

View file

@ -83,13 +83,6 @@ extern struct group_info init_groups;
#define INIT_IDS #define INIT_IDS
#endif #endif
/*
* Because of the reduced scope of CAP_SETPCAP when filesystem
* capabilities are in effect, it is safe to allow CAP_SETPCAP to
* be available in the default configuration.
*/
# define CAP_INIT_BSET CAP_FULL_SET
#ifdef CONFIG_RCU_BOOST #ifdef CONFIG_RCU_BOOST
#define INIT_TASK_RCU_BOOST() \ #define INIT_TASK_RCU_BOOST() \
.rcu_boost_mutex = NULL, .rcu_boost_mutex = NULL,

View file

@ -276,6 +276,19 @@ static inline key_serial_t key_serial(struct key *key)
return key ? key->serial : 0; return key ? key->serial : 0;
} }
/**
* key_is_instantiated - Determine if a key has been positively instantiated
* @key: The key to check.
*
* Return true if the specified key has been positively instantiated, false
* otherwise.
*/
static inline bool key_is_instantiated(const struct key *key)
{
return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
!test_bit(KEY_FLAG_NEGATIVE, &key->flags);
}
#define rcu_dereference_key(KEY) \ #define rcu_dereference_key(KEY) \
(rcu_dereference_protected((KEY)->payload.rcudata, \ (rcu_dereference_protected((KEY)->payload.rcudata, \
rwsem_is_locked(&((struct key *)(KEY))->sem))) rwsem_is_locked(&((struct key *)(KEY))->sem)))

View file

@ -24,6 +24,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/sysctl.h>
#define KMOD_PATH_LEN 256 #define KMOD_PATH_LEN 256
@ -109,6 +110,8 @@ call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
NULL, NULL, NULL); NULL, NULL, NULL);
} }
extern struct ctl_table usermodehelper_table[];
extern void usermodehelper_init(void); extern void usermodehelper_init(void);
extern int usermodehelper_disable(void); extern int usermodehelper_disable(void);

View file

@ -27,7 +27,7 @@
/* Auxiliary data to use in generating the audit record. */ /* Auxiliary data to use in generating the audit record. */
struct common_audit_data { struct common_audit_data {
char type; char type;
#define LSM_AUDIT_DATA_FS 1 #define LSM_AUDIT_DATA_PATH 1
#define LSM_AUDIT_DATA_NET 2 #define LSM_AUDIT_DATA_NET 2
#define LSM_AUDIT_DATA_CAP 3 #define LSM_AUDIT_DATA_CAP 3
#define LSM_AUDIT_DATA_IPC 4 #define LSM_AUDIT_DATA_IPC 4
@ -35,12 +35,13 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_KEY 6 #define LSM_AUDIT_DATA_KEY 6
#define LSM_AUDIT_DATA_NONE 7 #define LSM_AUDIT_DATA_NONE 7
#define LSM_AUDIT_DATA_KMOD 8 #define LSM_AUDIT_DATA_KMOD 8
#define LSM_AUDIT_DATA_INODE 9
#define LSM_AUDIT_DATA_DENTRY 10
struct task_struct *tsk; struct task_struct *tsk;
union { union {
struct {
struct path path; struct path path;
struct dentry *dentry;
struct inode *inode; struct inode *inode;
} fs;
struct { struct {
int netif; int netif;
struct sock *sk; struct sock *sk;

View file

@ -22,12 +22,8 @@
*/ */
const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET; const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
const kernel_cap_t __cap_full_set = CAP_FULL_SET;
const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET;
EXPORT_SYMBOL(__cap_empty_set); EXPORT_SYMBOL(__cap_empty_set);
EXPORT_SYMBOL(__cap_full_set);
EXPORT_SYMBOL(__cap_init_eff_set);
int file_caps_enabled = 1; int file_caps_enabled = 1;

View file

@ -49,10 +49,10 @@ struct cred init_cred = {
.magic = CRED_MAGIC, .magic = CRED_MAGIC,
#endif #endif
.securebits = SECUREBITS_DEFAULT, .securebits = SECUREBITS_DEFAULT,
.cap_inheritable = CAP_INIT_INH_SET, .cap_inheritable = CAP_EMPTY_SET,
.cap_permitted = CAP_FULL_SET, .cap_permitted = CAP_FULL_SET,
.cap_effective = CAP_INIT_EFF_SET, .cap_effective = CAP_FULL_SET,
.cap_bset = CAP_INIT_BSET, .cap_bset = CAP_FULL_SET,
.user = INIT_USER, .user = INIT_USER,
.user_ns = &init_user_ns, .user_ns = &init_user_ns,
.group_info = &init_groups, .group_info = &init_groups,

View file

@ -25,6 +25,7 @@
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/cred.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/fdtable.h> #include <linux/fdtable.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
@ -43,6 +44,13 @@ extern int max_threads;
static struct workqueue_struct *khelper_wq; static struct workqueue_struct *khelper_wq;
#define CAP_BSET (void *)1
#define CAP_PI (void *)2
static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
static DEFINE_SPINLOCK(umh_sysctl_lock);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
/* /*
@ -132,6 +140,7 @@ EXPORT_SYMBOL(__request_module);
static int ____call_usermodehelper(void *data) static int ____call_usermodehelper(void *data)
{ {
struct subprocess_info *sub_info = data; struct subprocess_info *sub_info = data;
struct cred *new;
int retval; int retval;
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
@ -153,6 +162,19 @@ static int ____call_usermodehelper(void *data)
goto fail; goto fail;
} }
retval = -ENOMEM;
new = prepare_kernel_cred(current);
if (!new)
goto fail;
spin_lock(&umh_sysctl_lock);
new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
new->cap_inheritable);
spin_unlock(&umh_sysctl_lock);
commit_creds(new);
retval = kernel_execve(sub_info->path, retval = kernel_execve(sub_info->path,
(const char *const *)sub_info->argv, (const char *const *)sub_info->argv,
(const char *const *)sub_info->envp); (const char *const *)sub_info->envp);
@ -420,6 +442,84 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
} }
EXPORT_SYMBOL(call_usermodehelper_exec); EXPORT_SYMBOL(call_usermodehelper_exec);
static int proc_cap_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
struct ctl_table t;
unsigned long cap_array[_KERNEL_CAPABILITY_U32S];
kernel_cap_t new_cap;
int err, i;
if (write && (!capable(CAP_SETPCAP) ||
!capable(CAP_SYS_MODULE)))
return -EPERM;
/*
* convert from the global kernel_cap_t to the ulong array to print to
* userspace if this is a read.
*/
spin_lock(&umh_sysctl_lock);
for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
if (table->data == CAP_BSET)
cap_array[i] = usermodehelper_bset.cap[i];
else if (table->data == CAP_PI)
cap_array[i] = usermodehelper_inheritable.cap[i];
else
BUG();
}
spin_unlock(&umh_sysctl_lock);
t = *table;
t.data = &cap_array;
/*
* actually read or write and array of ulongs from userspace. Remember
* these are least significant 32 bits first
*/
err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
if (err < 0)
return err;
/*
* convert from the sysctl array of ulongs to the kernel_cap_t
* internal representation
*/
for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)
new_cap.cap[i] = cap_array[i];
/*
* Drop everything not in the new_cap (but don't add things)
*/
spin_lock(&umh_sysctl_lock);
if (write) {
if (table->data == CAP_BSET)
usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap);
if (table->data == CAP_PI)
usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap);
}
spin_unlock(&umh_sysctl_lock);
return 0;
}
struct ctl_table usermodehelper_table[] = {
{
.procname = "bset",
.data = CAP_BSET,
.maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
.mode = 0600,
.proc_handler = proc_cap_handler,
},
{
.procname = "inheritable",
.data = CAP_PI,
.maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
.mode = 0600,
.proc_handler = proc_cap_handler,
},
{ }
};
void __init usermodehelper_init(void) void __init usermodehelper_init(void)
{ {
khelper_wq = create_singlethread_workqueue("khelper"); khelper_wq = create_singlethread_workqueue("khelper");

View file

@ -56,6 +56,7 @@
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/pipe_fs_i.h> #include <linux/pipe_fs_i.h>
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/kmod.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/processor.h> #include <asm/processor.h>
@ -615,6 +616,11 @@ static struct ctl_table kern_table[] = {
.mode = 0555, .mode = 0555,
.child = random_table, .child = random_table,
}, },
{
.procname = "usermodehelper",
.mode = 0555,
.child = usermodehelper_table,
},
{ {
.procname = "overflowuid", .procname = "overflowuid",
.data = &overflowuid, .data = &overflowuid,

View file

@ -88,7 +88,10 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
gfp_t flags) gfp_t flags)
{ {
struct flex_array *ret; struct flex_array *ret;
int max_size = FLEX_ARRAY_NR_BASE_PTRS * int max_size = 0;
if (element_size)
max_size = FLEX_ARRAY_NR_BASE_PTRS *
FLEX_ARRAY_ELEMENTS_PER_PART(element_size); FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
/* max_size will end up 0 if element_size > PAGE_SIZE */ /* max_size will end up 0 if element_size > PAGE_SIZE */
@ -183,15 +186,18 @@ __fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
gfp_t flags) gfp_t flags)
{ {
int part_nr = fa_element_to_part_nr(fa, element_nr); int part_nr;
struct flex_array_part *part; struct flex_array_part *part;
void *dst; void *dst;
if (element_nr >= fa->total_nr_elements) if (element_nr >= fa->total_nr_elements)
return -ENOSPC; return -ENOSPC;
if (!fa->element_size)
return 0;
if (elements_fit_in_base(fa)) if (elements_fit_in_base(fa))
part = (struct flex_array_part *)&fa->parts[0]; part = (struct flex_array_part *)&fa->parts[0];
else { else {
part_nr = fa_element_to_part_nr(fa, element_nr);
part = __fa_get_part(fa, part_nr, flags); part = __fa_get_part(fa, part_nr, flags);
if (!part) if (!part)
return -ENOMEM; return -ENOMEM;
@ -211,15 +217,18 @@ EXPORT_SYMBOL(flex_array_put);
*/ */
int flex_array_clear(struct flex_array *fa, unsigned int element_nr) int flex_array_clear(struct flex_array *fa, unsigned int element_nr)
{ {
int part_nr = fa_element_to_part_nr(fa, element_nr); int part_nr;
struct flex_array_part *part; struct flex_array_part *part;
void *dst; void *dst;
if (element_nr >= fa->total_nr_elements) if (element_nr >= fa->total_nr_elements)
return -ENOSPC; return -ENOSPC;
if (!fa->element_size)
return 0;
if (elements_fit_in_base(fa)) if (elements_fit_in_base(fa))
part = (struct flex_array_part *)&fa->parts[0]; part = (struct flex_array_part *)&fa->parts[0];
else { else {
part_nr = fa_element_to_part_nr(fa, element_nr);
part = fa->parts[part_nr]; part = fa->parts[part_nr];
if (!part) if (!part)
return -EINVAL; return -EINVAL;
@ -264,6 +273,8 @@ int flex_array_prealloc(struct flex_array *fa, unsigned int start,
if (end >= fa->total_nr_elements) if (end >= fa->total_nr_elements)
return -ENOSPC; return -ENOSPC;
if (!fa->element_size)
return 0;
if (elements_fit_in_base(fa)) if (elements_fit_in_base(fa))
return 0; return 0;
start_part = fa_element_to_part_nr(fa, start); start_part = fa_element_to_part_nr(fa, start);
@ -291,14 +302,17 @@ EXPORT_SYMBOL(flex_array_prealloc);
*/ */
void *flex_array_get(struct flex_array *fa, unsigned int element_nr) void *flex_array_get(struct flex_array *fa, unsigned int element_nr)
{ {
int part_nr = fa_element_to_part_nr(fa, element_nr); int part_nr;
struct flex_array_part *part; struct flex_array_part *part;
if (!fa->element_size)
return NULL;
if (element_nr >= fa->total_nr_elements) if (element_nr >= fa->total_nr_elements)
return NULL; return NULL;
if (elements_fit_in_base(fa)) if (elements_fit_in_base(fa))
part = (struct flex_array_part *)&fa->parts[0]; part = (struct flex_array_part *)&fa->parts[0];
else { else {
part_nr = fa_element_to_part_nr(fa, element_nr);
part = fa->parts[part_nr]; part = fa->parts[part_nr];
if (!part) if (!part)
return NULL; return NULL;
@ -353,7 +367,7 @@ int flex_array_shrink(struct flex_array *fa)
int part_nr; int part_nr;
int ret = 0; int ret = 0;
if (!fa->total_nr_elements) if (!fa->total_nr_elements || !fa->element_size)
return 0; return 0;
if (elements_fit_in_base(fa)) if (elements_fit_in_base(fa))
return ret; return ret;

View file

@ -212,11 +212,13 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
int err = key->type_data.x[0]; int err = key->type_data.x[0];
seq_puts(m, key->description); seq_puts(m, key->description);
if (key_is_instantiated(key)) {
if (err) if (err)
seq_printf(m, ": %d", err); seq_printf(m, ": %d", err);
else else
seq_printf(m, ": %u", key->datalen); seq_printf(m, ": %u", key->datalen);
} }
}
/* /*
* read the DNS data * read the DNS data

View file

@ -167,6 +167,7 @@ config INTEL_TXT
config LSM_MMAP_MIN_ADDR config LSM_MMAP_MIN_ADDR
int "Low address space for LSM to protect from user allocation" int "Low address space for LSM to protect from user allocation"
depends on SECURITY && SECURITY_SELINUX depends on SECURITY && SECURITY_SELINUX
default 32768 if ARM
default 65536 default 65536
help help
This is the portion of low virtual memory which should be protected This is the portion of low virtual memory which should be protected

View file

@ -529,15 +529,10 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
new->suid = new->fsuid = new->euid; new->suid = new->fsuid = new->euid;
new->sgid = new->fsgid = new->egid; new->sgid = new->fsgid = new->egid;
/* For init, we want to retain the capabilities set in the initial
* task. Thus we skip the usual capability rules
*/
if (!is_global_init(current)) {
if (effective) if (effective)
new->cap_effective = new->cap_permitted; new->cap_effective = new->cap_permitted;
else else
cap_clear(new->cap_effective); cap_clear(new->cap_effective);
}
bprm->cap_effective = effective; bprm->cap_effective = effective;
/* /*

View file

@ -109,11 +109,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const struct cred *cred, const struct cred *cred,
struct key_type *type, struct key_type *type,
const void *description, const void *description,
key_match_func_t match); key_match_func_t match,
bool no_state_check);
extern key_ref_t search_my_process_keyrings(struct key_type *type, extern key_ref_t search_my_process_keyrings(struct key_type *type,
const void *description, const void *description,
key_match_func_t match, key_match_func_t match,
bool no_state_check,
const struct cred *cred); const struct cred *cred);
extern key_ref_t search_process_keyrings(struct key_type *type, extern key_ref_t search_process_keyrings(struct key_type *type,
const void *description, const void *description,

View file

@ -206,8 +206,14 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
goto error5; goto error5;
} }
/* wait for the key to finish being constructed */
ret = wait_for_key_construction(key, 1);
if (ret < 0)
goto error6;
ret = key->serial; ret = key->serial;
error6:
key_put(key); key_put(key);
error5: error5:
key_type_put(ktype); key_type_put(ktype);

View file

@ -176,6 +176,7 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
else else
seq_puts(m, "[anon]"); seq_puts(m, "[anon]");
if (key_is_instantiated(keyring)) {
rcu_read_lock(); rcu_read_lock();
klist = rcu_dereference(keyring->payload.subscriptions); klist = rcu_dereference(keyring->payload.subscriptions);
if (klist) if (klist)
@ -184,6 +185,7 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
seq_puts(m, ": empty"); seq_puts(m, ": empty");
rcu_read_unlock(); rcu_read_unlock();
} }
}
/* /*
* Read a list of key IDs from the keyring's contents in binary form * Read a list of key IDs from the keyring's contents in binary form
@ -271,6 +273,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
* @type: The type of key to search for. * @type: The type of key to search for.
* @description: Parameter for @match. * @description: Parameter for @match.
* @match: Function to rule on whether or not a key is the one required. * @match: Function to rule on whether or not a key is the one required.
* @no_state_check: Don't check if a matching key is bad
* *
* Search the supplied keyring tree for a key that matches the criteria given. * Search the supplied keyring tree for a key that matches the criteria given.
* The root keyring and any linked keyrings must grant Search permission to the * The root keyring and any linked keyrings must grant Search permission to the
@ -303,7 +306,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const struct cred *cred, const struct cred *cred,
struct key_type *type, struct key_type *type,
const void *description, const void *description,
key_match_func_t match) key_match_func_t match,
bool no_state_check)
{ {
struct { struct {
struct keyring_list *keylist; struct keyring_list *keylist;
@ -345,6 +349,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
kflags = keyring->flags; kflags = keyring->flags;
if (keyring->type == type && match(keyring, description)) { if (keyring->type == type && match(keyring, description)) {
key = keyring; key = keyring;
if (no_state_check)
goto found;
/* check it isn't negative and hasn't expired or been /* check it isn't negative and hasn't expired or been
* revoked */ * revoked */
@ -384,11 +390,13 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
continue; continue;
/* skip revoked keys and expired keys */ /* skip revoked keys and expired keys */
if (!no_state_check) {
if (kflags & (1 << KEY_FLAG_REVOKED)) if (kflags & (1 << KEY_FLAG_REVOKED))
continue; continue;
if (key->expiry && now.tv_sec >= key->expiry) if (key->expiry && now.tv_sec >= key->expiry)
continue; continue;
}
/* keys that don't match */ /* keys that don't match */
if (!match(key, description)) if (!match(key, description))
@ -399,6 +407,9 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
cred, KEY_SEARCH) < 0) cred, KEY_SEARCH) < 0)
continue; continue;
if (no_state_check)
goto found;
/* we set a different error code if we pass a negative key */ /* we set a different error code if we pass a negative key */
if (kflags & (1 << KEY_FLAG_NEGATIVE)) { if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
err = key->type_data.reject_error; err = key->type_data.reject_error;
@ -478,7 +489,7 @@ key_ref_t keyring_search(key_ref_t keyring,
return ERR_PTR(-ENOKEY); return ERR_PTR(-ENOKEY);
return keyring_search_aux(keyring, current->cred, return keyring_search_aux(keyring, current->cred,
type, description, type->match); type, description, type->match, false);
} }
EXPORT_SYMBOL(keyring_search); EXPORT_SYMBOL(keyring_search);

View file

@ -199,7 +199,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
if (key->perm & KEY_POS_VIEW) { if (key->perm & KEY_POS_VIEW) {
skey_ref = search_my_process_keyrings(key->type, key, skey_ref = search_my_process_keyrings(key->type, key,
lookup_user_key_possessed, lookup_user_key_possessed,
cred); true, cred);
if (!IS_ERR(skey_ref)) { if (!IS_ERR(skey_ref)) {
key_ref_put(skey_ref); key_ref_put(skey_ref);
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);

View file

@ -331,6 +331,7 @@ void key_fsgid_changed(struct task_struct *tsk)
key_ref_t search_my_process_keyrings(struct key_type *type, key_ref_t search_my_process_keyrings(struct key_type *type,
const void *description, const void *description,
key_match_func_t match, key_match_func_t match,
bool no_state_check,
const struct cred *cred) const struct cred *cred)
{ {
key_ref_t key_ref, ret, err; key_ref_t key_ref, ret, err;
@ -350,7 +351,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
if (cred->thread_keyring) { if (cred->thread_keyring) {
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(cred->thread_keyring, 1), make_key_ref(cred->thread_keyring, 1),
cred, type, description, match); cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
@ -371,7 +372,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
if (cred->tgcred->process_keyring) { if (cred->tgcred->process_keyring) {
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(cred->tgcred->process_keyring, 1), make_key_ref(cred->tgcred->process_keyring, 1),
cred, type, description, match); cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
@ -395,7 +396,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
make_key_ref(rcu_dereference( make_key_ref(rcu_dereference(
cred->tgcred->session_keyring), cred->tgcred->session_keyring),
1), 1),
cred, type, description, match); cred, type, description, match, no_state_check);
rcu_read_unlock(); rcu_read_unlock();
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
@ -417,7 +418,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
else if (cred->user->session_keyring) { else if (cred->user->session_keyring) {
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(cred->user->session_keyring, 1), make_key_ref(cred->user->session_keyring, 1),
cred, type, description, match); cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
@ -459,7 +460,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
might_sleep(); might_sleep();
key_ref = search_my_process_keyrings(type, description, match, cred); key_ref = search_my_process_keyrings(type, description, match,
false, cred);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
err = key_ref; err = key_ref;

View file

@ -530,8 +530,7 @@ struct key *request_key_and_link(struct key_type *type,
dest_keyring, flags); dest_keyring, flags);
/* search all the process keyrings for a key */ /* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match, key_ref = search_process_keyrings(type, description, type->match, cred);
cred);
if (!IS_ERR(key_ref)) { if (!IS_ERR(key_ref)) {
key = key_ref_to_ptr(key_ref); key = key_ref_to_ptr(key_ref);

View file

@ -59,6 +59,7 @@ static void request_key_auth_describe(const struct key *key,
seq_puts(m, "key:"); seq_puts(m, "key:");
seq_puts(m, key->description); seq_puts(m, key->description);
if (key_is_instantiated(key))
seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
} }

View file

@ -157,7 +157,7 @@ EXPORT_SYMBOL_GPL(user_destroy);
void user_describe(const struct key *key, struct seq_file *m) void user_describe(const struct key *key, struct seq_file *m)
{ {
seq_puts(m, key->description); seq_puts(m, key->description);
if (key_is_instantiated(key))
seq_printf(m, ": %u", key->datalen); seq_printf(m, ": %u", key->datalen);
} }

View file

@ -210,7 +210,6 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
static void dump_common_audit_data(struct audit_buffer *ab, static void dump_common_audit_data(struct audit_buffer *ab,
struct common_audit_data *a) struct common_audit_data *a)
{ {
struct inode *inode = NULL;
struct task_struct *tsk = current; struct task_struct *tsk = current;
if (a->tsk) if (a->tsk)
@ -229,20 +228,36 @@ static void dump_common_audit_data(struct audit_buffer *ab,
case LSM_AUDIT_DATA_CAP: case LSM_AUDIT_DATA_CAP:
audit_log_format(ab, " capability=%d ", a->u.cap); audit_log_format(ab, " capability=%d ", a->u.cap);
break; break;
case LSM_AUDIT_DATA_FS: case LSM_AUDIT_DATA_PATH: {
if (a->u.fs.path.dentry) { struct inode *inode;
struct dentry *dentry = a->u.fs.path.dentry;
if (a->u.fs.path.mnt) { audit_log_d_path(ab, "path=", &a->u.path);
audit_log_d_path(ab, "path=", &a->u.fs.path);
} else { inode = a->u.path.dentry->d_inode;
audit_log_format(ab, " name="); if (inode)
audit_log_untrustedstring(ab, audit_log_format(ab, " dev=%s ino=%lu",
dentry->d_name.name); inode->i_sb->s_id,
inode->i_ino);
break;
} }
inode = dentry->d_inode; case LSM_AUDIT_DATA_DENTRY: {
} else if (a->u.fs.inode) { struct inode *inode;
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, a->u.dentry->d_name.name);
inode = a->u.dentry->d_inode;
if (inode)
audit_log_format(ab, " dev=%s ino=%lu",
inode->i_sb->s_id,
inode->i_ino);
break;
}
case LSM_AUDIT_DATA_INODE: {
struct dentry *dentry; struct dentry *dentry;
inode = a->u.fs.inode; struct inode *inode;
inode = a->u.inode;
dentry = d_find_alias(inode); dentry = d_find_alias(inode);
if (dentry) { if (dentry) {
audit_log_format(ab, " name="); audit_log_format(ab, " name=");
@ -250,12 +265,10 @@ static void dump_common_audit_data(struct audit_buffer *ab,
dentry->d_name.name); dentry->d_name.name);
dput(dentry); dput(dentry);
} }
} audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id,
if (inode)
audit_log_format(ab, " dev=%s ino=%lu",
inode->i_sb->s_id,
inode->i_ino); inode->i_ino);
break; break;
}
case LSM_AUDIT_DATA_TASK: case LSM_AUDIT_DATA_TASK:
tsk = a->u.tsk; tsk = a->u.tsk;
if (tsk && tsk->pid) { if (tsk && tsk->pid) {

View file

@ -526,7 +526,7 @@ int avc_audit(u32 ssid, u32 tsid,
* during retry. However this is logically just as if the operation * during retry. However this is logically just as if the operation
* happened a little later. * happened a little later.
*/ */
if ((a->type == LSM_AUDIT_DATA_FS) && if ((a->type == LSM_AUDIT_DATA_INODE) &&
(flags & IPERM_FLAG_RCU)) (flags & IPERM_FLAG_RCU))
return -ECHILD; return -ECHILD;

View file

@ -990,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m,
continue; continue;
default: default:
BUG(); BUG();
return;
}; };
/* we need a comma before each option */ /* we need a comma before each option */
seq_putc(m, ','); seq_putc(m, ',');
@ -1443,6 +1444,7 @@ static int task_has_capability(struct task_struct *tsk,
printk(KERN_ERR printk(KERN_ERR
"SELinux: out of range capability %d\n", cap); "SELinux: out of range capability %d\n", cap);
BUG(); BUG();
return -EINVAL;
} }
rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
@ -1487,8 +1489,8 @@ static int inode_has_perm(const struct cred *cred,
if (!adp) { if (!adp) {
adp = &ad; adp = &ad;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, INODE);
ad.u.fs.inode = inode; ad.u.inode = inode;
} }
return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
@ -1498,16 +1500,29 @@ static int inode_has_perm(const struct cred *cred,
the dentry to help the auditing code to more easily generate the the dentry to help the auditing code to more easily generate the
pathname if needed. */ pathname if needed. */
static inline int dentry_has_perm(const struct cred *cred, static inline int dentry_has_perm(const struct cred *cred,
struct vfsmount *mnt,
struct dentry *dentry, struct dentry *dentry,
u32 av) u32 av)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct common_audit_data ad; struct common_audit_data ad;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
ad.u.fs.path.mnt = mnt; ad.u.dentry = dentry;
ad.u.fs.path.dentry = dentry; return inode_has_perm(cred, inode, av, &ad, 0);
}
/* Same as inode_has_perm, but pass explicit audit data containing
the path to help the auditing code to more easily generate the
pathname if needed. */
static inline int path_has_perm(const struct cred *cred,
struct path *path,
u32 av)
{
struct inode *inode = path->dentry->d_inode;
struct common_audit_data ad;
COMMON_AUDIT_DATA_INIT(&ad, PATH);
ad.u.path = *path;
return inode_has_perm(cred, inode, av, &ad, 0); return inode_has_perm(cred, inode, av, &ad, 0);
} }
@ -1529,8 +1544,8 @@ static int file_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred); u32 sid = cred_sid(cred);
int rc; int rc;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, PATH);
ad.u.fs.path = file->f_path; ad.u.path = file->f_path;
if (sid != fsec->sid) { if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid, rc = avc_has_perm(sid, fsec->sid,
@ -1568,8 +1583,8 @@ static int may_create(struct inode *dir,
sid = tsec->sid; sid = tsec->sid;
newsid = tsec->create_sid; newsid = tsec->create_sid;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
ad.u.fs.path.dentry = dentry; ad.u.dentry = dentry;
rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH, DIR__ADD_NAME | DIR__SEARCH,
@ -1621,8 +1636,8 @@ static int may_link(struct inode *dir,
dsec = dir->i_security; dsec = dir->i_security;
isec = dentry->d_inode->i_security; isec = dentry->d_inode->i_security;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
ad.u.fs.path.dentry = dentry; ad.u.dentry = dentry;
av = DIR__SEARCH; av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
@ -1667,9 +1682,9 @@ static inline int may_rename(struct inode *old_dir,
old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
new_dsec = new_dir->i_security; new_dsec = new_dir->i_security;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
ad.u.fs.path.dentry = old_dentry; ad.u.dentry = old_dentry;
rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad); DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc) if (rc)
@ -1685,7 +1700,7 @@ static inline int may_rename(struct inode *old_dir,
return rc; return rc;
} }
ad.u.fs.path.dentry = new_dentry; ad.u.dentry = new_dentry;
av = DIR__ADD_NAME | DIR__SEARCH; av = DIR__ADD_NAME | DIR__SEARCH;
if (new_dentry->d_inode) if (new_dentry->d_inode)
av |= DIR__REMOVE_NAME; av |= DIR__REMOVE_NAME;
@ -1895,7 +1910,7 @@ static int selinux_quota_on(struct dentry *dentry)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); return dentry_has_perm(cred, dentry, FILE__QUOTAON);
} }
static int selinux_syslog(int type) static int selinux_syslog(int type)
@ -1992,8 +2007,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
return rc; return rc;
} }
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, PATH);
ad.u.fs.path = bprm->file->f_path; ad.u.path = bprm->file->f_path;
if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
new_tsec->sid = old_tsec->sid; new_tsec->sid = old_tsec->sid;
@ -2121,7 +2136,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
/* Revalidate access to inherited open files. */ /* Revalidate access to inherited open files. */
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, INODE);
spin_lock(&files->file_lock); spin_lock(&files->file_lock);
for (;;) { for (;;) {
@ -2469,8 +2484,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (flags & MS_KERNMOUNT) if (flags & MS_KERNMOUNT)
return 0; return 0;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
ad.u.fs.path.dentry = sb->s_root; ad.u.dentry = sb->s_root;
return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
} }
@ -2479,8 +2494,8 @@ static int selinux_sb_statfs(struct dentry *dentry)
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct common_audit_data ad; struct common_audit_data ad;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
ad.u.fs.path.dentry = dentry->d_sb->s_root; ad.u.dentry = dentry->d_sb->s_root;
return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
} }
@ -2496,8 +2511,7 @@ static int selinux_mount(char *dev_name,
return superblock_has_perm(cred, path->mnt->mnt_sb, return superblock_has_perm(cred, path->mnt->mnt_sb,
FILESYSTEM__REMOUNT, NULL); FILESYSTEM__REMOUNT, NULL);
else else
return dentry_has_perm(cred, path->mnt, path->dentry, return path_has_perm(cred, path, FILE__MOUNTON);
FILE__MOUNTON);
} }
static int selinux_umount(struct vfsmount *mnt, int flags) static int selinux_umount(struct vfsmount *mnt, int flags)
@ -2630,14 +2644,14 @@ static int selinux_inode_readlink(struct dentry *dentry)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
return dentry_has_perm(cred, NULL, dentry, FILE__READ); return dentry_has_perm(cred, dentry, FILE__READ);
} }
static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
return dentry_has_perm(cred, NULL, dentry, FILE__READ); return dentry_has_perm(cred, dentry, FILE__READ);
} }
static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags)
@ -2654,8 +2668,8 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag
if (!mask) if (!mask)
return 0; return 0;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, INODE);
ad.u.fs.inode = inode; ad.u.inode = inode;
if (from_access) if (from_access)
ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
@ -2680,16 +2694,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); return dentry_has_perm(cred, dentry, FILE__SETATTR);
return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); return dentry_has_perm(cred, dentry, FILE__WRITE);
} }
static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct path path;
return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR); path.dentry = dentry;
path.mnt = mnt;
return path_has_perm(cred, &path, FILE__GETATTR);
} }
static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
@ -2710,7 +2728,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
/* Not an attribute we recognize, so just check the /* Not an attribute we recognize, so just check the
ordinary setattr permission. */ ordinary setattr permission. */
return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); return dentry_has_perm(cred, dentry, FILE__SETATTR);
} }
static int selinux_inode_setxattr(struct dentry *dentry, const char *name, static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
@ -2733,8 +2751,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
if (!inode_owner_or_capable(inode)) if (!inode_owner_or_capable(inode))
return -EPERM; return -EPERM;
COMMON_AUDIT_DATA_INIT(&ad, FS); COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
ad.u.fs.path.dentry = dentry; ad.u.dentry = dentry;
rc = avc_has_perm(sid, isec->sid, isec->sclass, rc = avc_has_perm(sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad); FILE__RELABELFROM, &ad);
@ -2797,14 +2815,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); return dentry_has_perm(cred, dentry, FILE__GETATTR);
} }
static int selinux_inode_listxattr(struct dentry *dentry) static int selinux_inode_listxattr(struct dentry *dentry)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); return dentry_has_perm(cred, dentry, FILE__GETATTR);
} }
static int selinux_inode_removexattr(struct dentry *dentry, const char *name) static int selinux_inode_removexattr(struct dentry *dentry, const char *name)

View file

@ -30,13 +30,14 @@
#define POLICYDB_VERSION_PERMISSIVE 23 #define POLICYDB_VERSION_PERMISSIVE 23
#define POLICYDB_VERSION_BOUNDARY 24 #define POLICYDB_VERSION_BOUNDARY 24
#define POLICYDB_VERSION_FILENAME_TRANS 25 #define POLICYDB_VERSION_FILENAME_TRANS 25
#define POLICYDB_VERSION_ROLETRANS 26
/* Range of policy versions we understand*/ /* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
#else #else
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_FILENAME_TRANS #define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS
#endif #endif
/* Mask for just the mount related flags */ /* Mask for just the mount related flags */
@ -85,7 +86,7 @@ extern int selinux_policycap_openperm;
int security_mls_enabled(void); 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_read_policy(void **data, ssize_t *len); int security_read_policy(void **data, size_t *len);
size_t security_policydb_len(void); size_t security_policydb_len(void);
int security_policycap_supported(unsigned int req_cap); int security_policycap_supported(unsigned int req_cap);
@ -111,8 +112,8 @@ void security_compute_av_user(u32 ssid, u32 tsid,
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid); const struct qstr *qstr, u32 *out_sid);
int security_transition_sid_user(u32 ssid, u32 tsid, int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
u16 tclass, u32 *out_sid); const char *objname, u32 *out_sid);
int security_member_sid(u32 ssid, u32 tsid, int security_member_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid); u16 tclass, u32 *out_sid);

View file

@ -141,6 +141,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
break; break;
default: default:
BUG(); BUG();
return NULL;
} }
list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list) list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)

View file

@ -28,6 +28,7 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/kobject.h>
/* selinuxfs pseudo filesystem for exporting the security policy API. /* selinuxfs pseudo filesystem for exporting the security policy API.
Based on the proc code and the fs/nfsd/nfsctl.c code. */ Based on the proc code and the fs/nfsd/nfsctl.c code. */
@ -753,11 +754,13 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
static ssize_t sel_write_create(struct file *file, char *buf, size_t size) static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{ {
char *scon = NULL, *tcon = NULL; char *scon = NULL, *tcon = NULL;
char *namebuf = NULL, *objname = NULL;
u32 ssid, tsid, newsid; u32 ssid, tsid, newsid;
u16 tclass; u16 tclass;
ssize_t length; ssize_t length;
char *newcon = NULL; char *newcon = NULL;
u32 len; u32 len;
int nargs;
length = task_has_security(current, SECURITY__COMPUTE_CREATE); length = task_has_security(current, SECURITY__COMPUTE_CREATE);
if (length) if (length)
@ -773,10 +776,18 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (!tcon) if (!tcon)
goto out; goto out;
length = -EINVAL; length = -ENOMEM;
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) namebuf = kzalloc(size + 1, GFP_KERNEL);
if (!namebuf)
goto out; goto out;
length = -EINVAL;
nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
if (nargs < 3 || nargs > 4)
goto out;
if (nargs == 4)
objname = namebuf;
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
if (length) if (length)
goto out; goto out;
@ -785,7 +796,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (length) if (length)
goto out; goto out;
length = security_transition_sid_user(ssid, tsid, tclass, &newsid); length = security_transition_sid_user(ssid, tsid, tclass,
objname, &newsid);
if (length) if (length)
goto out; goto out;
@ -804,6 +816,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
length = len; length = len;
out: out:
kfree(newcon); kfree(newcon);
kfree(namebuf);
kfree(tcon); kfree(tcon);
kfree(scon); kfree(scon);
return length; return length;
@ -1901,6 +1914,7 @@ static struct file_system_type sel_fs_type = {
}; };
struct vfsmount *selinuxfs_mount; struct vfsmount *selinuxfs_mount;
static struct kobject *selinuxfs_kobj;
static int __init init_sel_fs(void) static int __init init_sel_fs(void)
{ {
@ -1908,9 +1922,16 @@ static int __init init_sel_fs(void)
if (!selinux_enabled) if (!selinux_enabled)
return 0; return 0;
selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
if (!selinuxfs_kobj)
return -ENOMEM;
err = register_filesystem(&sel_fs_type); err = register_filesystem(&sel_fs_type);
if (err) if (err) {
kobject_put(selinuxfs_kobj);
return err; return err;
}
selinuxfs_mount = kern_mount(&sel_fs_type); selinuxfs_mount = kern_mount(&sel_fs_type);
if (IS_ERR(selinuxfs_mount)) { if (IS_ERR(selinuxfs_mount)) {
@ -1927,6 +1948,7 @@ __initcall(init_sel_fs);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE #ifdef CONFIG_SECURITY_SELINUX_DISABLE
void exit_sel_fs(void) void exit_sel_fs(void)
{ {
kobject_put(selinuxfs_kobj);
unregister_filesystem(&sel_fs_type); unregister_filesystem(&sel_fs_type);
} }
#endif #endif

View file

@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM, .sym_num = SYM_NUM,
.ocon_num = OCON_NUM, .ocon_num = OCON_NUM,
}, },
{
.version = POLICYDB_VERSION_ROLETRANS,
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
}; };
static struct policydb_compat_info *policydb_lookup_compat(int version) static struct policydb_compat_info *policydb_lookup_compat(int version)
@ -179,6 +184,43 @@ static int roles_init(struct policydb *p)
return rc; return rc;
} }
static u32 filenametr_hash(struct hashtab *h, const void *k)
{
const struct filename_trans *ft = k;
unsigned long hash;
unsigned int byte_num;
unsigned char focus;
hash = ft->stype ^ ft->ttype ^ ft->tclass;
byte_num = 0;
while ((focus = ft->name[byte_num++]))
hash = partial_name_hash(focus, hash);
return hash & (h->size - 1);
}
static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
{
const struct filename_trans *ft1 = k1;
const struct filename_trans *ft2 = k2;
int v;
v = ft1->stype - ft2->stype;
if (v)
return v;
v = ft1->ttype - ft2->ttype;
if (v)
return v;
v = ft1->tclass - ft2->tclass;
if (v)
return v;
return strcmp(ft1->name, ft2->name);
}
static u32 rangetr_hash(struct hashtab *h, const void *k) static u32 rangetr_hash(struct hashtab *h, const void *k)
{ {
const struct range_trans *key = k; const struct range_trans *key = k;
@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p)
if (rc) if (rc)
goto out; goto out;
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
if (!p->filename_trans)
goto out;
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
if (!p->range_tr) if (!p->range_tr)
goto out; goto out;
ebitmap_init(&p->filename_trans_ttypes);
ebitmap_init(&p->policycaps); ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map); ebitmap_init(&p->permissive_map);
return 0; return 0;
out: out:
hashtab_destroy(p->filename_trans);
hashtab_destroy(p->range_tr);
for (i = 0; i < SYM_NUM; i++) for (i = 0; i < SYM_NUM; i++)
hashtab_destroy(p->symtab[i].table); hashtab_destroy(p->symtab[i].table);
return rc; return rc;
@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
}; };
#ifdef DEBUG_HASHES #ifdef DEBUG_HASHES
static void symtab_hash_eval(struct symtab *s) static void hash_eval(struct hashtab *h, const char *hash_name)
{ {
int i;
for (i = 0; i < SYM_NUM; i++) {
struct hashtab *h = s[i].table;
struct hashtab_info info; struct hashtab_info info;
hashtab_stat(h, &info); hashtab_stat(h, &info);
printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, "
"longest chain length %d\n", symtab_name[i], h->nel, "longest chain length %d\n", hash_name, h->nel,
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) static void symtab_hash_eval(struct symtab *s)
{ {
struct hashtab_info info; int i;
hashtab_stat(h, &info); for (i = 0; i < SYM_NUM; i++)
printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " hash_eval(s[i].table, symtab_name[i]);
"longest chain length %d\n", h->nel,
info.slots_used, h->size, info.max_chain_len);
} }
#else #else
static inline void rangetr_hash_eval(struct hashtab *h) static inline void hash_eval(struct hashtab *h, char *hash_name)
{ {
} }
#endif #endif
@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
cat_destroy, cat_destroy,
}; };
static int filenametr_destroy(void *key, void *datum, void *p)
{
struct filename_trans *ft = key;
kfree(ft->name);
kfree(key);
kfree(datum);
cond_resched();
return 0;
}
static int range_tr_destroy(void *key, void *datum, void *p) static int range_tr_destroy(void *key, void *datum, void *p)
{ {
struct mls_range *rt = datum; struct mls_range *rt = datum;
@ -709,7 +762,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 filename_trans *ft, *nft;
for (i = 0; i < SYM_NUM; i++) { for (i = 0; i < SYM_NUM; i++) {
cond_resched(); cond_resched();
@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p)
} }
kfree(lra); kfree(lra);
hashtab_map(p->filename_trans, filenametr_destroy, NULL);
hashtab_destroy(p->filename_trans);
hashtab_map(p->range_tr, range_tr_destroy, NULL); hashtab_map(p->range_tr, range_tr_destroy, NULL);
hashtab_destroy(p->range_tr); hashtab_destroy(p->range_tr);
@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p)
flex_array_free(p->type_attr_map_array); flex_array_free(p->type_attr_map_array);
} }
ft = p->filename_trans; ebitmap_destroy(&p->filename_trans_ttypes);
while (ft) {
nft = ft->next;
kfree(ft->name);
kfree(ft);
ft = nft;
}
ebitmap_destroy(&p->policycaps); ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map); ebitmap_destroy(&p->permissive_map);
@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp)
rt = NULL; rt = NULL;
r = NULL; r = NULL;
} }
rangetr_hash_eval(p->range_tr); hash_eval(p->range_tr, "rangetr");
rc = 0; rc = 0;
out: out:
kfree(rt); kfree(rt);
@ -1805,9 +1853,10 @@ static int range_read(struct policydb *p, void *fp)
static int filename_trans_read(struct policydb *p, void *fp) static int filename_trans_read(struct policydb *p, void *fp)
{ {
struct filename_trans *ft, *last; struct filename_trans *ft;
u32 nel, len; struct filename_trans_datum *otype;
char *name; char *name;
u32 nel, len;
__le32 buf[4]; __le32 buf[4];
int rc, i; int rc, i;
@ -1816,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp)
rc = next_entry(buf, fp, sizeof(u32)); rc = next_entry(buf, fp, sizeof(u32));
if (rc) if (rc)
goto out; return rc;
nel = le32_to_cpu(buf[0]); nel = le32_to_cpu(buf[0]);
last = p->filename_trans;
while (last && last->next)
last = last->next;
for (i = 0; i < nel; i++) { for (i = 0; i < nel; i++) {
ft = NULL;
otype = NULL;
name = NULL;
rc = -ENOMEM; rc = -ENOMEM;
ft = kzalloc(sizeof(*ft), GFP_KERNEL); ft = kzalloc(sizeof(*ft), GFP_KERNEL);
if (!ft) if (!ft)
goto out; goto out;
/* add it to the tail of the list */ rc = -ENOMEM;
if (!last) otype = kmalloc(sizeof(*otype), GFP_KERNEL);
p->filename_trans = ft; if (!otype)
else goto out;
last->next = ft;
last = ft;
/* length of the path component string */ /* length of the path component string */
rc = next_entry(buf, fp, sizeof(u32)); rc = next_entry(buf, fp, sizeof(u32));
@ -1862,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp)
ft->stype = le32_to_cpu(buf[0]); ft->stype = le32_to_cpu(buf[0]);
ft->ttype = le32_to_cpu(buf[1]); ft->ttype = le32_to_cpu(buf[1]);
ft->tclass = le32_to_cpu(buf[2]); ft->tclass = le32_to_cpu(buf[2]);
ft->otype = le32_to_cpu(buf[3]);
otype->otype = le32_to_cpu(buf[3]);
rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
if (rc)
goto out;
hashtab_insert(p->filename_trans, ft, otype);
} }
rc = 0; hash_eval(p->filename_trans, "filenametr");
return 0;
out: out:
kfree(ft);
kfree(name);
kfree(otype);
return rc; return rc;
} }
@ -2266,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp)
p->symtab[i].nprim = nprim; p->symtab[i].nprim = nprim;
} }
rc = -EINVAL;
p->process_class = string_to_security_class(p, "process");
if (!p->process_class)
goto bad;
rc = avtab_read(&p->te_avtab, fp, p); rc = avtab_read(&p->te_avtab, fp, p);
if (rc) if (rc)
goto bad; goto bad;
@ -2298,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp)
tr->role = le32_to_cpu(buf[0]); tr->role = le32_to_cpu(buf[0]);
tr->type = le32_to_cpu(buf[1]); tr->type = le32_to_cpu(buf[1]);
tr->new_role = le32_to_cpu(buf[2]); tr->new_role = le32_to_cpu(buf[2]);
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
goto bad;
tr->tclass = le32_to_cpu(buf[0]);
} else
tr->tclass = p->process_class;
if (!policydb_role_isvalid(p, tr->role) || if (!policydb_role_isvalid(p, tr->role) ||
!policydb_type_isvalid(p, tr->type) || !policydb_type_isvalid(p, tr->type) ||
!policydb_class_isvalid(p, tr->tclass) ||
!policydb_role_isvalid(p, tr->new_role)) !policydb_role_isvalid(p, tr->new_role))
goto bad; goto bad;
ltr = tr; ltr = tr;
@ -2340,11 +2413,6 @@ int policydb_read(struct policydb *p, void *fp)
if (rc) if (rc)
goto bad; goto bad;
rc = -EINVAL;
p->process_class = string_to_security_class(p, "process");
if (!p->process_class)
goto bad;
rc = -EINVAL; rc = -EINVAL;
p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
@ -2517,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr)
return 0; return 0;
} }
static int role_trans_write(struct role_trans *r, void *fp) static int role_trans_write(struct policydb *p, void *fp)
{ {
struct role_trans *r = p->role_tr;
struct role_trans *tr; struct role_trans *tr;
u32 buf[3]; u32 buf[3];
size_t nel; size_t nel;
@ -2538,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp)
rc = put_entry(buf, sizeof(u32), 3, fp); rc = put_entry(buf, sizeof(u32), 3, fp);
if (rc) if (rc)
return rc; return rc;
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
buf[0] = cpu_to_le32(tr->tclass);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
}
} }
return 0; return 0;
@ -3045,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp)
return 0; return 0;
} }
static int range_count(void *key, void *data, void *ptr) static int hashtab_cnt(void *key, void *data, void *ptr)
{ {
int *cnt = ptr; int *cnt = ptr;
*cnt = *cnt + 1; *cnt = *cnt + 1;
@ -3093,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp)
/* count the number of entries in the hashtab */ /* count the number of entries in the hashtab */
nel = 0; nel = 0;
rc = hashtab_map(p->range_tr, range_count, &nel); rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
if (rc) if (rc)
return rc; return rc;
@ -3110,22 +3185,15 @@ static int range_write(struct policydb *p, void *fp)
return 0; return 0;
} }
static int filename_trans_write(struct policydb *p, void *fp) static int filename_write_helper(void *key, void *data, void *ptr)
{ {
struct filename_trans *ft;
u32 len, nel = 0;
__le32 buf[4]; __le32 buf[4];
struct filename_trans *ft = key;
struct filename_trans_datum *otype = data;
void *fp = ptr;
int rc; int rc;
u32 len;
for (ft = p->filename_trans; ft; ft = ft->next)
nel++;
buf[0] = cpu_to_le32(nel);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
for (ft = p->filename_trans; ft; ft = ft->next) {
len = strlen(ft->name); len = strlen(ft->name);
buf[0] = cpu_to_le32(len); buf[0] = cpu_to_le32(len);
rc = put_entry(buf, sizeof(u32), 1, fp); rc = put_entry(buf, sizeof(u32), 1, fp);
@ -3139,14 +3207,38 @@ static int filename_trans_write(struct policydb *p, void *fp)
buf[0] = ft->stype; buf[0] = ft->stype;
buf[1] = ft->ttype; buf[1] = ft->ttype;
buf[2] = ft->tclass; buf[2] = ft->tclass;
buf[3] = ft->otype; buf[3] = otype->otype;
rc = put_entry(buf, sizeof(u32), 4, fp); rc = put_entry(buf, sizeof(u32), 4, fp);
if (rc) if (rc)
return rc; return rc;
}
return 0; return 0;
} }
static int filename_trans_write(struct policydb *p, void *fp)
{
u32 nel;
__le32 buf[1];
int rc;
nel = 0;
rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
if (rc)
return rc;
buf[0] = cpu_to_le32(nel);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
if (rc)
return rc;
return 0;
}
/* /*
* Write the configuration data in a policy database * Write the configuration data in a policy database
* structure to a policy database binary representation * structure to a policy database binary representation
@ -3249,7 +3341,7 @@ int policydb_write(struct policydb *p, void *fp)
if (rc) if (rc)
return rc; return rc;
rc = role_trans_write(p->role_tr, fp); rc = role_trans_write(p, fp);
if (rc) if (rc)
return rc; return rc;

View file

@ -72,17 +72,20 @@ struct role_datum {
struct role_trans { struct role_trans {
u32 role; /* current role */ u32 role; /* current role */
u32 type; /* program executable type */ u32 type; /* program executable type, or new object type */
u32 tclass; /* process class, or new object class */
u32 new_role; /* new role */ u32 new_role; /* new role */
struct role_trans *next; struct role_trans *next;
}; };
struct filename_trans { struct filename_trans {
struct filename_trans *next;
u32 stype; /* current process */ u32 stype; /* current process */
u32 ttype; /* parent dir context */ u32 ttype; /* parent dir context */
u16 tclass; /* class of new object */ u16 tclass; /* class of new object */
const char *name; /* last path component */ const char *name; /* last path component */
};
struct filename_trans_datum {
u32 otype; /* expected of new object */ u32 otype; /* expected of new object */
}; };
@ -227,7 +230,10 @@ struct policydb {
struct role_trans *role_tr; struct role_trans *role_tr;
/* file transitions with the last path component */ /* file transitions with the last path component */
struct filename_trans *filename_trans; /* quickly exclude lookups when parent ttype has no rules */
struct ebitmap filename_trans_ttypes;
/* actual set of filename_trans rules */
struct hashtab *filename_trans;
/* bools indexed by (value - 1) */ /* bools indexed by (value - 1) */
struct cond_bool_datum **bool_val_to_struct; struct cond_bool_datum **bool_val_to_struct;

View file

@ -1359,26 +1359,35 @@ static int compute_sid_handle_invalid_context(
} }
static void filename_compute_type(struct policydb *p, struct context *newcontext, static void filename_compute_type(struct policydb *p, struct context *newcontext,
u32 scon, u32 tcon, u16 tclass, u32 stype, u32 ttype, u16 tclass,
const struct qstr *qstr) const char *objname)
{ {
struct filename_trans *ft; struct filename_trans ft;
for (ft = p->filename_trans; ft; ft = ft->next) { struct filename_trans_datum *otype;
if (ft->stype == scon &&
ft->ttype == tcon && /*
ft->tclass == tclass && * Most filename trans rules are going to live in specific directories
!strcmp(ft->name, qstr->name)) { * like /dev or /var/run. This bitmap will quickly skip rule searches
newcontext->type = ft->otype; * if the ttype does not contain any rules.
*/
if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
return; return;
}
} ft.stype = stype;
ft.ttype = ttype;
ft.tclass = tclass;
ft.name = objname;
otype = hashtab_search(p->filename_trans, &ft);
if (otype)
newcontext->type = otype->otype;
} }
static int security_compute_sid(u32 ssid, static int security_compute_sid(u32 ssid,
u32 tsid, u32 tsid,
u16 orig_tclass, u16 orig_tclass,
u32 specified, u32 specified,
const struct qstr *qstr, const char *objname,
u32 *out_sid, u32 *out_sid,
bool kern) bool kern)
{ {
@ -1478,26 +1487,24 @@ static int security_compute_sid(u32 ssid,
newcontext.type = avdatum->data; newcontext.type = avdatum->data;
} }
/* if we have a qstr this is a file trans check so check those rules */ /* if we have a objname this is a file trans check so check those rules */
if (qstr) if (objname)
filename_compute_type(&policydb, &newcontext, scontext->type, filename_compute_type(&policydb, &newcontext, scontext->type,
tcontext->type, tclass, qstr); tcontext->type, tclass, objname);
/* Check for class-specific changes. */ /* Check for class-specific changes. */
if (tclass == policydb.process_class) {
if (specified & AVTAB_TRANSITION) { if (specified & AVTAB_TRANSITION) {
/* Look for a role transition rule. */ /* Look for a role transition rule. */
for (roletr = policydb.role_tr; roletr; for (roletr = policydb.role_tr; roletr; roletr = roletr->next) {
roletr = roletr->next) { if ((roletr->role == scontext->role) &&
if (roletr->role == scontext->role && (roletr->type == tcontext->type) &&
roletr->type == tcontext->type) { (roletr->tclass == tclass)) {
/* Use the role transition rule. */ /* Use the role transition rule. */
newcontext.role = roletr->new_role; newcontext.role = roletr->new_role;
break; break;
} }
} }
} }
}
/* Set the MLS attributes. /* Set the MLS attributes.
This is done last because it may allocate memory. */ This is done last because it may allocate memory. */
@ -1541,13 +1548,14 @@ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid) const struct qstr *qstr, u32 *out_sid)
{ {
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
qstr, out_sid, true); qstr ? qstr->name : NULL, out_sid, true);
} }
int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
const char *objname, u32 *out_sid)
{ {
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
NULL, out_sid, false); objname, out_sid, false);
} }
/** /**
@ -3190,7 +3198,7 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
* @len: length of data in bytes * @len: length of data in bytes
* *
*/ */
int security_read_policy(void **data, ssize_t *len) int security_read_policy(void **data, size_t *len)
{ {
int rc; int rc;
struct policy_file fp; struct policy_file fp;

View file

@ -316,22 +316,17 @@ static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a,
struct dentry *d) struct dentry *d)
{ {
a->a.u.fs.path.dentry = d; a->a.u.dentry = d;
}
static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a,
struct vfsmount *m)
{
a->a.u.fs.path.mnt = m;
} }
static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a,
struct inode *i) struct inode *i)
{ {
a->a.u.fs.inode = i; a->a.u.inode = i;
} }
static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a,
struct path p) struct path p)
{ {
a->a.u.fs.path = p; a->a.u.path = p;
} }
static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
struct sock *sk) struct sock *sk)

View file

@ -383,7 +383,7 @@ static int smack_sb_statfs(struct dentry *dentry)
int rc; int rc;
struct smk_audit_info ad; struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
@ -407,7 +407,7 @@ static int smack_sb_mount(char *dev_name, struct path *path,
struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; struct superblock_smack *sbp = path->mnt->mnt_sb->s_security;
struct smk_audit_info ad; struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, *path); smk_ad_setfield_u_fs_path(&ad, *path);
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
@ -425,10 +425,13 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
{ {
struct superblock_smack *sbp; struct superblock_smack *sbp;
struct smk_audit_info ad; struct smk_audit_info ad;
struct path path;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); path.dentry = mnt->mnt_root;
smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root); path.mnt = mnt;
smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, path);
sbp = mnt->mnt_sb->s_security; sbp = mnt->mnt_sb->s_security;
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
@ -563,7 +566,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
struct smk_audit_info ad; struct smk_audit_info ad;
int rc; int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
isp = smk_of_inode(old_dentry->d_inode); isp = smk_of_inode(old_dentry->d_inode);
@ -592,7 +595,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
struct smk_audit_info ad; struct smk_audit_info ad;
int rc; int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
/* /*
@ -623,7 +626,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
struct smk_audit_info ad; struct smk_audit_info ad;
int rc; int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
/* /*
@ -663,7 +666,7 @@ static int smack_inode_rename(struct inode *old_inode,
char *isp; char *isp;
struct smk_audit_info ad; struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
isp = smk_of_inode(old_dentry->d_inode); isp = smk_of_inode(old_dentry->d_inode);
@ -700,7 +703,7 @@ static int smack_inode_permission(struct inode *inode, int mask, unsigned flags)
/* May be droppable after audit */ /* May be droppable after audit */
if (flags & IPERM_FLAG_RCU) if (flags & IPERM_FLAG_RCU)
return -ECHILD; return -ECHILD;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, inode); smk_ad_setfield_u_fs_inode(&ad, inode);
return smk_curacc(smk_of_inode(inode), mask, &ad); return smk_curacc(smk_of_inode(inode), mask, &ad);
} }
@ -720,7 +723,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
*/ */
if (iattr->ia_valid & ATTR_FORCE) if (iattr->ia_valid & ATTR_FORCE)
return 0; return 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
@ -736,10 +739,13 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{ {
struct smk_audit_info ad; struct smk_audit_info ad;
struct path path;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); path.dentry = dentry;
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); path.mnt = mnt;
smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, path);
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
} }
@ -784,7 +790,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
} else } else
rc = cap_inode_setxattr(dentry, name, value, size, flags); rc = cap_inode_setxattr(dentry, name, value, size, flags);
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
if (rc == 0) if (rc == 0)
@ -845,7 +851,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
{ {
struct smk_audit_info ad; struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
@ -877,7 +883,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
} else } else
rc = cap_inode_removexattr(dentry, name); rc = cap_inode_removexattr(dentry, name);
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
if (rc == 0) if (rc == 0)
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
@ -1047,7 +1053,7 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
int rc = 0; int rc = 0;
struct smk_audit_info ad; struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path); smk_ad_setfield_u_fs_path(&ad, file->f_path);
if (_IOC_DIR(cmd) & _IOC_WRITE) if (_IOC_DIR(cmd) & _IOC_WRITE)
@ -1070,8 +1076,8 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
{ {
struct smk_audit_info ad; struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); smk_ad_setfield_u_fs_path(&ad, file->f_path);
return smk_curacc(file->f_security, MAY_WRITE, &ad); return smk_curacc(file->f_security, MAY_WRITE, &ad);
} }
@ -1089,7 +1095,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
struct smk_audit_info ad; struct smk_audit_info ad;
int rc; int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path); smk_ad_setfield_u_fs_path(&ad, file->f_path);
switch (cmd) { switch (cmd) {

View file

@ -108,10 +108,9 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)
head->read_user_buf += len; head->read_user_buf += len;
w += len; w += len;
} }
if (*w) {
head->r.w[0] = w; head->r.w[0] = w;
if (*w)
return false; return false;
}
/* Add '\0' for query. */ /* Add '\0' for query. */
if (head->poll) { if (head->poll) {
if (!head->read_user_buf_avail || if (!head->read_user_buf_avail ||
@ -459,8 +458,16 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
if (profile == &tomoyo_default_profile) if (profile == &tomoyo_default_profile)
return -EINVAL; return -EINVAL;
if (!strcmp(data, "COMMENT")) { if (!strcmp(data, "COMMENT")) {
const struct tomoyo_path_info *old_comment = profile->comment; static DEFINE_SPINLOCK(lock);
profile->comment = tomoyo_get_name(cp); const struct tomoyo_path_info *new_comment
= tomoyo_get_name(cp);
const struct tomoyo_path_info *old_comment;
if (!new_comment)
return -ENOMEM;
spin_lock(&lock);
old_comment = profile->comment;
profile->comment = new_comment;
spin_unlock(&lock);
tomoyo_put_name(old_comment); tomoyo_put_name(old_comment);
return 0; return 0;
} }

View file

@ -1011,7 +1011,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
break; break;
case TOMOYO_TYPE_RMDIR: case TOMOYO_TYPE_RMDIR:
case TOMOYO_TYPE_CHROOT: case TOMOYO_TYPE_CHROOT:
case TOMOYO_TYPE_UMOUNT:
tomoyo_add_slash(&buf); tomoyo_add_slash(&buf);
break; break;
} }

View file

@ -75,6 +75,7 @@ void *tomoyo_commit_ok(void *data, const unsigned int size)
memset(data, 0, size); memset(data, 0, size);
return ptr; return ptr;
} }
kfree(ptr);
return NULL; return NULL;
} }

View file

@ -143,6 +143,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
goto out; goto out;
} }
requested_dev_name = tomoyo_realpath_from_path(&path); requested_dev_name = tomoyo_realpath_from_path(&path);
path_put(&path);
if (!requested_dev_name) { if (!requested_dev_name) {
error = -ENOENT; error = -ENOENT;
goto out; goto out;

View file

@ -390,7 +390,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname)
if (!cp) if (!cp)
break; break;
if (*domainname != '/' || if (*domainname != '/' ||
!tomoyo_correct_word2(domainname, cp - domainname - 1)) !tomoyo_correct_word2(domainname, cp - domainname))
goto out; goto out;
domainname = cp + 1; domainname = cp + 1;
} }