Commit b0ca118d 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: (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
  ...
parents 2bb732cd b7b57551
...@@ -5592,10 +5592,11 @@ M: James Morris <jmorris@namei.org> ...@@ -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>
......
...@@ -820,6 +820,8 @@ static int load_flat_shared_library(int id, struct lib_info *libs) ...@@ -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) ...@@ -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))
......
...@@ -417,7 +417,6 @@ extern const kernel_cap_t __cap_init_eff_set; ...@@ -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; ...@@ -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))
......
...@@ -83,13 +83,6 @@ extern struct group_info init_groups; ...@@ -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,
......
...@@ -276,6 +276,19 @@ static inline key_serial_t key_serial(struct key *key) ...@@ -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)))
......
...@@ -24,6 +24,7 @@ ...@@ -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) ...@@ -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);
......
...@@ -27,7 +27,7 @@ ...@@ -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 { ...@@ -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;
......
...@@ -22,12 +22,8 @@ ...@@ -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;
......
...@@ -49,10 +49,10 @@ struct cred init_cred = { ...@@ -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,
......
...@@ -25,6 +25,7 @@ ...@@ -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; ...@@ -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); ...@@ -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) ...@@ -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, ...@@ -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");
......
...@@ -56,6 +56,7 @@ ...@@ -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[] = { ...@@ -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,
......
...@@ -88,8 +88,11 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total, ...@@ -88,8 +88,11 @@ 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;
FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
if (element_size)
max_size = FLEX_ARRAY_NR_BASE_PTRS *
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 */
if (total > max_size) if (total > max_size)
...@@ -183,15 +186,18 @@ __fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags) ...@@ -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); ...@@ -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, ...@@ -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); ...@@ -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) ...@@ -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;
......
...@@ -212,10 +212,12 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m) ...@@ -212,10 +212,12 @@ 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 (err) if (key_is_instantiated(key)) {
seq_printf(m, ": %d", err); if (err)
else seq_printf(m, ": %d", err);
seq_printf(m, ": %u", key->datalen); else
seq_printf(m, ": %u", key->datalen);
}
} }
/* /*
......
...@@ -167,6 +167,7 @@ config INTEL_TXT ...@@ -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
......
...@@ -529,15 +529,10 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) ...@@ -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 if (effective)
* task. Thus we skip the usual capability rules new->cap_effective = new->cap_permitted;
*/ else
if (!is_global_init(current)) { cap_clear(new->cap_effective);
if (effective)
new->cap_effective = new->cap_permitted;
else
cap_clear(new->cap_effective);
}
bprm->cap_effective = effective; bprm->cap_effective = effective;
/* /*
......
...@@ -109,11 +109,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -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,
......
...@@ -206,8 +206,14 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, ...@@ -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);
......
...@@ -176,13 +176,15 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) ...@@ -176,13 +176,15 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
else else
seq_puts(m, "[anon]"); seq_puts(m, "[anon]");
rcu_read_lock(); if (key_is_instantiated(keyring)) {
klist = rcu_dereference(keyring->payload.subscriptions); rcu_read_lock();
if (klist) klist = rcu_dereference(keyring->payload.subscriptions);
seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); if (klist)
else seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
seq_puts(m, ": empty"); else
rcu_read_unlock(); seq_puts(m, ": empty");
rcu_read_unlock();
}
} }
/* /*
...@@ -271,6 +273,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 (kflags & (1 << KEY_FLAG_REVOKED)) if (!no_state_check) {
continue; if (kflags & (1 << KEY_FLAG_REVOKED))
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, ...@@ -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, ...@@ -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);
......
...@@ -199,7 +199,7 @@ static int proc_keys_show(struct seq_file *m, void *v) ...@@ -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);
......
...@@ -331,6 +331,7 @@ void key_fsgid_changed(struct task_struct *tsk) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -530,8 +530,7 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -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);
......
...@@ -59,7 +59,8 @@ static void request_key_auth_describe(const struct key *key, ...@@ -59,7 +59,8 @@ 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);
seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); if (key_is_instantiated(key))
seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
} }
/* /*
......
...@@ -157,8 +157,8 @@ EXPORT_SYMBOL_GPL(user_destroy); ...@@ -157,8 +157,8 @@ 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);
} }
EXPORT_SYMBOL_GPL(user_describe); EXPORT_SYMBOL_GPL(user_describe);
......
...@@ -210,7 +210,6 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, ...@@ -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,33 +228,47 @@ static void dump_common_audit_data(struct audit_buffer *ab, ...@@ -229,33 +228,47 @@ 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=");
audit_log_untrustedstring(ab,
dentry->d_name.name);
}
inode = dentry->d_inode;
} else if (a->u.fs.inode) {
struct dentry *dentry;
inode = a->u.fs.inode;
dentry = d_find_alias(inode);
if (dentry) {
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab,
dentry->d_name.name);
dput(dentry);
}
}
if (inode) if (inode)
audit_log_format(ab, " dev=%s ino=%lu", audit_log_format(ab, " dev=%s ino=%lu",
inode->i_sb->s_id, inode->i_sb->s_id,
inode->i_ino); inode->i_ino);
break; break;
}
case LSM_AUDIT_DATA_DENTRY: {
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 inode *inode;
inode = a->u.inode;
dentry = d_find_alias(inode);
if (dentry) {
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab,
dentry->d_name.name);
dput(dentry);
}
audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id,
inode->i_ino);
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) {
......
...@@ -526,7 +526,7 @@ int avc_audit(u32 ssid, u32 tsid, ...@@ -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;
......
...@@ -990,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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;
path.dentry = dentry;
path.mnt = mnt;
return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR); 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) ...@@ -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, ...@@ -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) ...@@ -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)
......
...@@ -30,13 +30,14 @@ ...@@ -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; ...@@ -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, ...@@ -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);
......
...@@ -141,6 +141,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) ...@@ -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)
......
...@@ -28,6 +28,7 @@ ...@@ -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) ...@@ -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,9 +776,17 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) ...@@ -773,9 +776,17 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (!tcon) if (!tcon)
goto out; goto out;
length = -ENOMEM;
namebuf = kzalloc(size + 1, GFP_KERNEL);
if (!namebuf)
goto out;
length = -EINVAL; length = -EINVAL;
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
if (nargs < 3 || nargs > 4)
goto out; 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)
...@@ -785,7 +796,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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); ...@@ -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
This diff is collapsed.
...@@ -72,17 +72,20 @@ struct role_datum { ...@@ -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 { ...@@ -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;
......
...@@ -1359,26 +1359,35 @@ static int compute_sid_handle_invalid_context( ...@@ -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.
return; */
} if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
} 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,23 +1487,21 @@ static int security_compute_sid(u32 ssid, ...@@ -1478,23 +1487,21 @@ 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; roletr = roletr->next) {
for (roletr = policydb.role_tr; roletr; if ((roletr->role == scontext->role) &&
roletr = roletr->next) { (roletr->type == tcontext->type) &&
if (roletr->role == scontext->role && (roletr->tclass == tclass)) {
roletr->type == tcontext->type) { /* Use the role transition rule. */
/* Use the role transition rule. */ newcontext.role = roletr->new_role;
newcontext.role = roletr->new_role; break;
break;
}
} }
} }
} }
...@@ -1541,13 +1548,14 @@ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, ...@@ -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) ...@@ -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;
......
...@@ -316,22 +316,17 @@ static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, ...@@ -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)
......
...@@ -383,7 +383,7 @@ static int smack_sb_statfs(struct dentry *dentry) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) {
......
...@@ -108,10 +108,9 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head) ...@@ -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) ...@@ -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;
} }
......
...@@ -1011,7 +1011,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path) ...@@ -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;
} }
......
...@@ -75,6 +75,7 @@ void *tomoyo_commit_ok(void *data, const unsigned int size) ...@@ -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;
} }
......
...@@ -143,6 +143,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, ...@@ -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;
......
...@@ -390,7 +390,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname) ...@@ -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;
} }
......
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