# SPDX-License-Identifier: GPL-2.0
+CONTEXT_ANALYSIS := y
+
obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o
targets += builtin-policy.h
*/
static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
...)
+ __must_hold(&head->io_sem)
{
va_list args;
size_t len;
*
* Returns nothing.
*/
-static void tomoyo_print_number_union_nospace
-(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
+static void
+tomoyo_print_number_union_nospace(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
+ __must_hold(&head->io_sem)
{
if (ptr->group) {
tomoyo_set_string(head, "@");
*/
static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
const struct tomoyo_number_union *ptr)
+ __must_hold(&head->io_sem)
{
tomoyo_set_space(head);
tomoyo_print_number_union_nospace(head, ptr);
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
char *data = head->write_buf;
unsigned int i;
* Caller prints functionality's name.
*/
static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
+ __must_hold(&head->io_sem)
{
tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
tomoyo_mode[config & 3],
* Returns nothing.
*/
static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
u8 index;
struct tomoyo_policy_namespace *ns =
*/
static int tomoyo_update_manager_entry(const char *manager,
const bool is_delete)
+ __must_hold_shared(&tomoyo_ss)
{
struct tomoyo_manager e = { };
struct tomoyo_acl_param param = {
* Caller holds tomoyo_read_lock().
*/
static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
char *data = head->write_buf;
* Caller holds tomoyo_read_lock().
*/
static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
+ __must_hold_shared(&tomoyo_ss)
{
if (head->r.eof)
return;
* Caller holds tomoyo_read_lock().
*/
static bool tomoyo_manager(void)
+ __must_hold_shared(&tomoyo_ss)
{
struct tomoyo_manager *ptr;
const char *exe;
*/
static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
const char *data)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
unsigned int pid;
struct tomoyo_domain_info *domain = NULL;
* Caller holds tomoyo_read_lock().
*/
static int tomoyo_write_task(struct tomoyo_acl_param *param)
+ __must_hold_shared(&tomoyo_ss)
{
int error = -EINVAL;
* Caller holds tomoyo_read_lock().
*/
static int tomoyo_delete_domain(char *domainname)
+ __must_hold_shared(&tomoyo_ss)
{
struct tomoyo_domain_info *domain;
struct tomoyo_path_info name;
static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
struct list_head *list, char *data,
const bool is_delete)
+ __must_hold_shared(&tomoyo_ss)
{
struct tomoyo_acl_param param = {
.ns = ns,
* Caller holds tomoyo_read_lock().
*/
static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
char *data = head->write_buf;
struct tomoyo_policy_namespace *ns;
*/
static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
const struct tomoyo_condition *cond)
+ __must_hold(&head->io_sem)
{
switch (head->r.cond_step) {
case 0:
*/
static void tomoyo_set_group(struct tomoyo_io_buffer *head,
const char *category)
+ __must_hold(&head->io_sem)
{
if (head->type == TOMOYO_EXCEPTIONPOLICY) {
tomoyo_print_namespace(head);
*/
static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
struct tomoyo_acl_info *acl)
+ __must_hold(&head->io_sem)
{
const u8 acl_type = acl->type;
bool first = true;
*/
static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
struct list_head *list)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
list_for_each_cookie(head->r.acl, list) {
struct tomoyo_acl_info *ptr =
* Caller holds tomoyo_read_lock().
*/
static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
if (head->r.eof)
return;
* using read()/write() interface rather than sysctl() interface.
*/
static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
char *buf = head->write_buf;
bool global_pid = false;
* Caller holds tomoyo_read_lock().
*/
static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
const bool is_delete = head->w.is_delete;
struct tomoyo_acl_param param = {
* Caller holds tomoyo_read_lock().
*/
static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
* Caller holds tomoyo_read_lock().
*/
static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
+ __must_hold_shared(&tomoyo_ss)
{
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
* Caller holds tomoyo_read_lock().
*/
static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
* Returns nothing.
*/
static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
+ __must_hold_shared(&tomoyo_ss)
{
char *buffer;
char *realpath = NULL;
* @head: Pointer to "struct tomoyo_io_buffer".
*/
static void tomoyo_read_query(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
struct list_head *tmp;
unsigned int pos = 0;
* Returns 0 on success, -EINVAL otherwise.
*/
static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
char *data = head->write_buf;
struct list_head *tmp;
* Returns version information.
*/
static void tomoyo_read_version(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
if (!head->r.eof) {
tomoyo_io_printf(head, "2.6.0");
* Returns nothing.
*/
static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
u8 i;
unsigned int total = 0;
* Returns 0.
*/
static int tomoyo_write_stat(struct tomoyo_io_buffer *head)
+ __must_hold(&head->io_sem)
{
char *data = head->write_buf;
u8 i;
* Caller holds tomoyo_read_lock().
*/
static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
+ __must_hold_shared(&tomoyo_ss)
+ __must_hold(&head->io_sem)
{
/* Delete request? */
head->w.is_delete = !strncmp(line, "delete ", 7);
break;
*end = '\0';
tomoyo_normalize_line(start);
- head.write_buf = start;
- tomoyo_parse_policy(&head, start);
+ /* head is stack-local and not shared. */
+ context_unsafe(
+ head.write_buf = start;
+ tomoyo_parse_policy(&head, start);
+ );
start = end + 1;
}
}
bool is_delete;
} w;
/* Buffer for reading. */
- char *read_buf;
+ char *read_buf __guarded_by(&io_sem);
/* Size of read buffer. */
- size_t readbuf_size;
+ size_t readbuf_size __guarded_by(&io_sem);
/* Buffer for writing. */
- char *write_buf;
+ char *write_buf __guarded_by(&io_sem);
/* Size of write buffer. */
- size_t writebuf_size;
+ size_t writebuf_size __guarded_by(&io_sem);
/* Type of this interface. */
enum tomoyo_securityfs_interface_index type;
/* Users counter protected by tomoyo_io_buffer_list_lock. */
struct tomoyo_domain_info *old_domain_info;
};
+/********** External variable definitions. **********/
+
+extern bool tomoyo_policy_loaded;
+extern int tomoyo_enabled;
+extern const char * const tomoyo_condition_keyword
+[TOMOYO_MAX_CONDITION_KEYWORD];
+extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
+extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+ + TOMOYO_MAX_MAC_CATEGORY_INDEX];
+extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE];
+extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
+extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX];
+extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION];
+extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX];
+extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION];
+extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION];
+extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION];
+extern struct list_head tomoyo_condition_list;
+extern struct list_head tomoyo_domain_list;
+extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+extern struct list_head tomoyo_namespace_list;
+extern struct mutex tomoyo_policy_lock;
+extern struct srcu_struct tomoyo_ss;
+extern struct tomoyo_domain_info tomoyo_kernel_domain;
+extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
+extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
+extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+extern struct lsm_blob_sizes tomoyo_blob_sizes;
+
/********** Function prototypes. **********/
int tomoyo_interface_init(void);
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
const struct path *path, const int flag);
void tomoyo_close_control(struct tomoyo_io_buffer *head);
-int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env);
+int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env) __must_hold_shared(&tomoyo_ss);
int tomoyo_execute_permission(struct tomoyo_request_info *r,
- const struct tomoyo_path_info *filename);
-int tomoyo_find_next_domain(struct linux_binprm *bprm);
+ const struct tomoyo_path_info *filename) __must_hold_shared(&tomoyo_ss);
+int tomoyo_find_next_domain(struct linux_binprm *bprm) __must_hold_shared(&tomoyo_ss);
int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
const u8 index);
int tomoyo_init_request_info(struct tomoyo_request_info *r,
int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
int size);
int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+ __must_hold_shared(&tomoyo_ss)
__printf(2, 3);
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
struct tomoyo_acl_param *param,
const unsigned long value, const u8 type);
void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
-void tomoyo_read_log(struct tomoyo_io_buffer *head);
+void tomoyo_read_log(struct tomoyo_io_buffer *head) __must_hold(&head->io_sem);
void tomoyo_update_stat(const u8 index);
void tomoyo_warn_oom(const char *function);
void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
va_list args) __printf(3, 0);
-/********** External variable definitions. **********/
-
-extern bool tomoyo_policy_loaded;
-extern int tomoyo_enabled;
-extern const char * const tomoyo_condition_keyword
-[TOMOYO_MAX_CONDITION_KEYWORD];
-extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
-extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
- + TOMOYO_MAX_MAC_CATEGORY_INDEX];
-extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE];
-extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
-extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX];
-extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION];
-extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX];
-extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION];
-extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION];
-extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION];
-extern struct list_head tomoyo_condition_list;
-extern struct list_head tomoyo_domain_list;
-extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
-extern struct list_head tomoyo_namespace_list;
-extern struct mutex tomoyo_policy_lock;
-extern struct srcu_struct tomoyo_ss;
-extern struct tomoyo_domain_info tomoyo_kernel_domain;
-extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
-extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
-extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
-extern struct lsm_blob_sizes tomoyo_blob_sizes;
-
/********** Inlined functions. **********/
/**
* Returns index number for tomoyo_read_unlock().
*/
static inline int tomoyo_read_lock(void)
+ __acquires_shared(&tomoyo_ss)
{
return srcu_read_lock(&tomoyo_ss);
}
* Returns nothing.
*/
static inline void tomoyo_read_unlock(int idx)
+ __releases_shared(&tomoyo_ss)
{
srcu_read_unlock(&tomoyo_ss, idx);
}
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_environ(struct tomoyo_execve *ee)
+ __must_hold_shared(&tomoyo_ss)
{
struct tomoyo_request_info *r = &ee->r;
struct linux_binprm *bprm = ee->bprm;
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_env_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
return tomoyo_supervisor(r, "misc env %s\n",
r->param.environ.name->name);
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
[r->param.path.operation],
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
[tomoyo_pp2mac[r->param.path2.operation]],
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
tomoyo_mac_keywords
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
const u8 type = r->param.path_number.operation;
u8 radix;
*/
static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
const struct tomoyo_path_info *filename)
+ __must_hold_shared(&tomoyo_ss)
{
int error;
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr);
kfree(ptr);
}
-
-/* The list for "struct tomoyo_io_buffer". */
-static LIST_HEAD(tomoyo_io_buffer_list);
/* Lock for protecting tomoyo_io_buffer_list. */
static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
+/* The list for "struct tomoyo_io_buffer". */
+static __guarded_by(&tomoyo_io_buffer_list_lock) LIST_HEAD(tomoyo_io_buffer_list);
/**
* tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
*/
static void tomoyo_try_to_gc(const enum tomoyo_policy_id type,
struct list_head *element)
+ __must_hold(&tomoyo_policy_lock)
{
/*
* __list_del_entry() guarantees that the list element became no longer
*/
static void tomoyo_collect_member(const enum tomoyo_policy_id id,
struct list_head *member_list)
+ __must_hold(&tomoyo_policy_lock)
{
struct tomoyo_acl_head *member;
struct tomoyo_acl_head *tmp;
* Returns nothing.
*/
static void tomoyo_collect_acl(struct list_head *list)
+ __must_hold(&tomoyo_policy_lock)
{
struct tomoyo_acl_info *acl;
struct tomoyo_acl_info *tmp;
if (head->users)
continue;
list_del(&head->list);
- kfree(head->read_buf);
- kfree(head->write_buf);
+ /* Safe destruction because no users are left. */
+ context_unsafe(
+ kfree(head->read_buf);
+ kfree(head->write_buf);
+ );
kfree(head);
}
spin_unlock(&tomoyo_io_buffer_list_lock);
head->users = 1;
list_add(&head->list, &tomoyo_io_buffer_list);
} else {
- is_write = head->write_buf != NULL;
+ /*
+ * tomoyo_write_control() can concurrently update write_buf from
+ * a non-NULL to new non-NULL pointer with io_sem held.
+ */
+ is_write = data_race(head->write_buf != NULL);
if (!--head->users) {
list_del(&head->list);
- kfree(head->read_buf);
- kfree(head->write_buf);
+ /* Safe destruction because no users are left. */
+ context_unsafe(
+ kfree(head->read_buf);
+ kfree(head->write_buf);
+ );
kfree(head);
}
}
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n",
r->param.mount.dev->name,
const char *dev_name,
const struct path *dir, const char *type,
unsigned long flags)
+ __must_hold_shared(&tomoyo_ss)
{
struct tomoyo_obj_info obj = { };
struct path path;
static int tomoyo_audit_net_log(struct tomoyo_request_info *r,
const char *family, const u8 protocol,
const u8 operation, const char *address)
+ __must_hold_shared(&tomoyo_ss)
{
return tomoyo_supervisor(r, "network %s %s %s %s\n", family,
tomoyo_proto_keyword[protocol],
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_inet_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
char buf[128];
int len;
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_audit_unix_log(struct tomoyo_request_info *r)
+ __must_hold_shared(&tomoyo_ss)
{
return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol,
r->param.unix_network.operation,