#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared"
/**
- * tomoyo_encode2: Encode binary string to ascii string.
+ * tomoyo_audit_mount_log - Audit mount log.
*
- * @str: String in binary format.
+ * @r: Pointer to "struct tomoyo_request_info".
*
- * Returns pointer to @str in ascii format on success, NULL otherwise.
- *
- * This function uses kzalloc(), so caller must kfree() if this function
- * didn't return NULL.
+ * Returns 0 on success, negative value otherwise.
*/
-static char *tomoyo_encode2(const char *str)
+static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
{
- int len = 0;
- const char *p = str;
- char *cp;
- char *cp0;
- if (!p)
- return NULL;
- while (*p) {
- const unsigned char c = *p++;
- if (c == '\\')
- len += 2;
- else if (c > ' ' && c < 127)
- len++;
- else
- len += 4;
- }
- len++;
- /* Reserve space for appending "/". */
- cp = kzalloc(len + 10, GFP_NOFS);
- if (!cp)
- return NULL;
- cp0 = cp;
- p = str;
- while (*p) {
- const unsigned char c = *p++;
- if (c == '\\') {
- *cp++ = '\\';
- *cp++ = '\\';
- } else if (c > ' ' && c < 127) {
- *cp++ = c;
- } else {
- *cp++ = '\\';
- *cp++ = (c >> 6) + '0';
- *cp++ = ((c >> 3) & 7) + '0';
- *cp++ = (c & 7) + '0';
- }
- }
- return cp0;
+ const char *dev = r->param.mount.dev->name;
+ const char *dir = r->param.mount.dir->name;
+ const char *type = r->param.mount.type->name;
+ const unsigned long flags = r->param.mount.flags;
+ if (r->granted)
+ return 0;
+ if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD))
+ tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags);
+ else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD)
+ || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD))
+ tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir,
+ flags);
+ else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD))
+ tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags);
+ else
+ tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir,
+ flags);
+ return tomoyo_supervisor(r,
+ TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
+ tomoyo_file_pattern(r->param.mount.dev),
+ tomoyo_file_pattern(r->param.mount.dir), type,
+ flags);
+}
+
+static bool tomoyo_check_mount_acl(const struct tomoyo_request_info *r,
+ const struct tomoyo_acl_info *ptr)
+{
+ const struct tomoyo_mount_acl *acl =
+ container_of(ptr, typeof(*acl), head);
+ return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) &&
+ tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) &&
+ tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
+ (!r->param.mount.need_dev ||
+ tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name));
}
/**
struct path *dir, char *type, unsigned long flags)
{
struct path path;
- struct tomoyo_acl_info *ptr;
struct file_system_type *fstype = NULL;
const char *requested_type = NULL;
const char *requested_dir_name = NULL;
int error = -ENOMEM;
/* Get fstype. */
- requested_type = tomoyo_encode2(type);
+ requested_type = tomoyo_encode(type);
if (!requested_type)
goto out;
rtype.name = requested_type;
/* Map dev_name to "<NULL>" if no dev_name given. */
if (!dev_name)
dev_name = "<NULL>";
- requested_dev_name = tomoyo_encode2(dev_name);
+ requested_dev_name = tomoyo_encode(dev_name);
if (!requested_dev_name) {
error = -ENOMEM;
goto out;
}
rdev.name = requested_dev_name;
tomoyo_fill_path_info(&rdev);
- list_for_each_entry_rcu(ptr, &r->domain->acl_info_list, list) {
- struct tomoyo_mount_acl *acl;
- if (ptr->type != TOMOYO_TYPE_MOUNT_ACL)
- continue;
- acl = container_of(ptr, struct tomoyo_mount_acl, head);
- if (acl->is_deleted ||
- !tomoyo_compare_number_union(flags, &acl->flags) ||
- !tomoyo_compare_name_union(&rtype, &acl->fs_type) ||
- !tomoyo_compare_name_union(&rdir, &acl->dir_name) ||
- (need_dev &&
- !tomoyo_compare_name_union(&rdev, &acl->dev_name)))
- continue;
- error = 0;
- break;
- }
- if (error) {
- const char *dev = tomoyo_get_file_pattern(&rdev)->name;
- const char *dir = tomoyo_get_file_pattern(&rdir)->name;
- int len = strlen(dev) + strlen(dir) + strlen(requested_type)
- + 64;
- char *buf = kzalloc(len, GFP_NOFS);
- if (buf) {
- snprintf(buf, len - 1, "%s %s %s 0x%lX",
- dev, dir, requested_type, flags);
- tomoyo_write_mount_policy(buf, r->domain, false);
- kfree(buf);
- }
- }
+ r->param_type = TOMOYO_TYPE_MOUNT_ACL;
+ r->param.mount.need_dev = need_dev;
+ r->param.mount.dev = &rdev;
+ r->param.mount.dir = &rdir;
+ r->param.mount.type = &rtype;
+ r->param.mount.flags = flags;
+ do {
+ tomoyo_check_acl(r, tomoyo_check_mount_acl);
+ error = tomoyo_audit_mount_log(r);
+ } while (error == TOMOYO_RETRY_REQUEST);
out:
kfree(requested_dev_name);
kfree(requested_dir_name);
TOMOYO_MOUNT_MAKE_SHARED_KEYWORD,
flags & ~MS_SHARED);
else
- error = tomoyo_mount_acl2(r, dev_name, dir, type, flags);
+ do {
+ error = tomoyo_mount_acl2(r, dev_name, dir, type,
+ flags);
+ } while (error == TOMOYO_RETRY_REQUEST);
if (r->mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
int error;
int idx;
- if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED)
+ if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
+ == TOMOYO_CONFIG_DISABLED)
return 0;
if (!type)
type = "<NULL>";
return error;
}
+static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
+ const struct tomoyo_acl_info *b)
+{
+ const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
+ const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
+ return tomoyo_same_acl_head(&p1->head, &p2->head) &&
+ tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
+ tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
+ tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
+ tomoyo_same_number_union(&p1->flags, &p2->flags);
+}
+
/**
* tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list.
*
* @is_delete: True if it is a delete request.
*
* Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
*/
int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain,
const bool is_delete)
{
- struct tomoyo_acl_info *ptr;
struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
int error = is_delete ? -ENOENT : -ENOMEM;
char *w[4];
!tomoyo_parse_name_union(w[2], &e.fs_type) ||
!tomoyo_parse_number_union(w[3], &e.flags))
goto out;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- goto out;
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- struct tomoyo_mount_acl *acl =
- container_of(ptr, struct tomoyo_mount_acl, head);
- if (!tomoyo_is_same_mount_acl(acl, &e))
- continue;
- acl->is_deleted = is_delete;
- error = 0;
- break;
- }
- if (!is_delete && error) {
- struct tomoyo_mount_acl *entry =
- tomoyo_commit_ok(&e, sizeof(e));
- if (entry) {
- list_add_tail_rcu(&entry->head.list,
- &domain->acl_info_list);
- error = 0;
- }
- }
- mutex_unlock(&tomoyo_policy_lock);
+ error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
+ tomoyo_same_mount_acl, NULL);
out:
tomoyo_put_name_union(&e.dev_name);
tomoyo_put_name_union(&e.dir_name);