|
@@ -12,39 +12,49 @@
|
|
|
#include "common.h"
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
-/* Keyword array for single path operations. */
|
|
|
+/* Keyword array for operations with one pathname. */
|
|
|
static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
|
|
|
[TOMOYO_TYPE_READ_WRITE] = "read/write",
|
|
|
[TOMOYO_TYPE_EXECUTE] = "execute",
|
|
|
[TOMOYO_TYPE_READ] = "read",
|
|
|
[TOMOYO_TYPE_WRITE] = "write",
|
|
|
- [TOMOYO_TYPE_CREATE] = "create",
|
|
|
[TOMOYO_TYPE_UNLINK] = "unlink",
|
|
|
- [TOMOYO_TYPE_MKDIR] = "mkdir",
|
|
|
[TOMOYO_TYPE_RMDIR] = "rmdir",
|
|
|
- [TOMOYO_TYPE_MKFIFO] = "mkfifo",
|
|
|
- [TOMOYO_TYPE_MKSOCK] = "mksock",
|
|
|
- [TOMOYO_TYPE_MKBLOCK] = "mkblock",
|
|
|
- [TOMOYO_TYPE_MKCHAR] = "mkchar",
|
|
|
[TOMOYO_TYPE_TRUNCATE] = "truncate",
|
|
|
[TOMOYO_TYPE_SYMLINK] = "symlink",
|
|
|
[TOMOYO_TYPE_REWRITE] = "rewrite",
|
|
|
- [TOMOYO_TYPE_IOCTL] = "ioctl",
|
|
|
- [TOMOYO_TYPE_CHMOD] = "chmod",
|
|
|
- [TOMOYO_TYPE_CHOWN] = "chown",
|
|
|
- [TOMOYO_TYPE_CHGRP] = "chgrp",
|
|
|
[TOMOYO_TYPE_CHROOT] = "chroot",
|
|
|
[TOMOYO_TYPE_MOUNT] = "mount",
|
|
|
[TOMOYO_TYPE_UMOUNT] = "unmount",
|
|
|
};
|
|
|
|
|
|
-/* Keyword array for double path operations. */
|
|
|
+/* Keyword array for operations with one pathname and three numbers. */
|
|
|
+static const char *tomoyo_path_number3_keyword
|
|
|
+[TOMOYO_MAX_PATH_NUMBER3_OPERATION] = {
|
|
|
+ [TOMOYO_TYPE_MKBLOCK] = "mkblock",
|
|
|
+ [TOMOYO_TYPE_MKCHAR] = "mkchar",
|
|
|
+};
|
|
|
+
|
|
|
+/* Keyword array for operations with two pathnames. */
|
|
|
static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
|
|
|
- [TOMOYO_TYPE_LINK] = "link",
|
|
|
- [TOMOYO_TYPE_RENAME] = "rename",
|
|
|
+ [TOMOYO_TYPE_LINK] = "link",
|
|
|
+ [TOMOYO_TYPE_RENAME] = "rename",
|
|
|
[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
|
|
|
};
|
|
|
|
|
|
+/* Keyword array for operations with one pathname and one number. */
|
|
|
+static const char *tomoyo_path_number_keyword
|
|
|
+[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
|
|
|
+ [TOMOYO_TYPE_CREATE] = "create",
|
|
|
+ [TOMOYO_TYPE_MKDIR] = "mkdir",
|
|
|
+ [TOMOYO_TYPE_MKFIFO] = "mkfifo",
|
|
|
+ [TOMOYO_TYPE_MKSOCK] = "mksock",
|
|
|
+ [TOMOYO_TYPE_IOCTL] = "ioctl",
|
|
|
+ [TOMOYO_TYPE_CHMOD] = "chmod",
|
|
|
+ [TOMOYO_TYPE_CHOWN] = "chown",
|
|
|
+ [TOMOYO_TYPE_CHGRP] = "chgrp",
|
|
|
+};
|
|
|
+
|
|
|
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
|
|
|
{
|
|
|
if (!ptr)
|
|
@@ -158,6 +168,19 @@ const char *tomoyo_path2keyword(const u8 operation)
|
|
|
? tomoyo_path_keyword[operation] : NULL;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tomoyo_path_number32keyword - Get the name of path/number/number/number operations.
|
|
|
+ *
|
|
|
+ * @operation: Type of operation.
|
|
|
+ *
|
|
|
+ * Returns the name of path/number/number/number operation.
|
|
|
+ */
|
|
|
+const char *tomoyo_path_number32keyword(const u8 operation)
|
|
|
+{
|
|
|
+ return (operation < TOMOYO_MAX_PATH_NUMBER3_OPERATION)
|
|
|
+ ? tomoyo_path_number3_keyword[operation] : NULL;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tomoyo_path22keyword - Get the name of double path operation.
|
|
|
*
|
|
@@ -171,6 +194,19 @@ const char *tomoyo_path22keyword(const u8 operation)
|
|
|
? tomoyo_path2_keyword[operation] : NULL;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tomoyo_path_number2keyword - Get the name of path/number operations.
|
|
|
+ *
|
|
|
+ * @operation: Type of operation.
|
|
|
+ *
|
|
|
+ * Returns the name of path/number operation.
|
|
|
+ */
|
|
|
+const char *tomoyo_path_number2keyword(const u8 operation)
|
|
|
+{
|
|
|
+ return (operation < TOMOYO_MAX_PATH_NUMBER_OPERATION)
|
|
|
+ ? tomoyo_path_number_keyword[operation] : NULL;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tomoyo_strendswith - Check whether the token ends with the given token.
|
|
|
*
|
|
@@ -665,8 +701,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
|
|
|
/**
|
|
|
* tomoyo_update_file_acl - Update file's read/write/execute ACL.
|
|
|
*
|
|
|
- * @filename: Filename.
|
|
|
* @perm: Permission (between 1 to 7).
|
|
|
+ * @filename: Filename.
|
|
|
* @domain: Pointer to "struct tomoyo_domain_info".
|
|
|
* @is_delete: True if it is a delete request.
|
|
|
*
|
|
@@ -679,7 +715,7 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
|
|
|
*
|
|
|
* Caller holds tomoyo_read_lock().
|
|
|
*/
|
|
|
-static int tomoyo_update_file_acl(const char *filename, u8 perm,
|
|
|
+static int tomoyo_update_file_acl(u8 perm, const char *filename,
|
|
|
struct tomoyo_domain_info * const domain,
|
|
|
const bool is_delete)
|
|
|
{
|
|
@@ -731,14 +767,8 @@ static int tomoyo_path_acl(const struct tomoyo_request_info *r,
|
|
|
if (ptr->type != TOMOYO_TYPE_PATH_ACL)
|
|
|
continue;
|
|
|
acl = container_of(ptr, struct tomoyo_path_acl, head);
|
|
|
- if (perm <= 0xFFFF) {
|
|
|
- if (!(acl->perm & perm))
|
|
|
- continue;
|
|
|
- } else {
|
|
|
- if (!(acl->perm_high & (perm >> 16)))
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (!tomoyo_compare_name_union_pattern(filename, &acl->name,
|
|
|
+ if (!(acl->perm & perm) ||
|
|
|
+ !tomoyo_compare_name_union_pattern(filename, &acl->name,
|
|
|
may_use_pattern))
|
|
|
continue;
|
|
|
error = 0;
|
|
@@ -796,60 +826,12 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r,
|
|
|
/* Don't use patterns for execute permission. */
|
|
|
const struct tomoyo_path_info *patterned_file = (mode != 1) ?
|
|
|
tomoyo_get_file_pattern(filename) : filename;
|
|
|
- tomoyo_update_file_acl(patterned_file->name, mode,
|
|
|
- r->domain, false);
|
|
|
+ tomoyo_update_file_acl(mode, patterned_file->name, r->domain,
|
|
|
+ false);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * tomoyo_write_file_policy - Update file related list.
|
|
|
- *
|
|
|
- * @data: String to parse.
|
|
|
- * @domain: Pointer to "struct tomoyo_domain_info".
|
|
|
- * @is_delete: True if it is a delete request.
|
|
|
- *
|
|
|
- * Returns 0 on success, negative value otherwise.
|
|
|
- *
|
|
|
- * Caller holds tomoyo_read_lock().
|
|
|
- */
|
|
|
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
|
|
|
- const bool is_delete)
|
|
|
-{
|
|
|
- char *filename = strchr(data, ' ');
|
|
|
- char *filename2;
|
|
|
- unsigned int perm;
|
|
|
- u8 type;
|
|
|
-
|
|
|
- if (!filename)
|
|
|
- return -EINVAL;
|
|
|
- *filename++ = '\0';
|
|
|
- if (sscanf(data, "%u", &perm) == 1)
|
|
|
- return tomoyo_update_file_acl(filename, (u8) perm, domain,
|
|
|
- is_delete);
|
|
|
- if (strncmp(data, "allow_", 6))
|
|
|
- goto out;
|
|
|
- data += 6;
|
|
|
- for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
|
|
|
- if (strcmp(data, tomoyo_path_keyword[type]))
|
|
|
- continue;
|
|
|
- return tomoyo_update_path_acl(type, filename, domain,
|
|
|
- is_delete);
|
|
|
- }
|
|
|
- filename2 = strchr(filename, ' ');
|
|
|
- if (!filename2)
|
|
|
- goto out;
|
|
|
- *filename2++ = '\0';
|
|
|
- for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
|
|
|
- if (strcmp(data, tomoyo_path2_keyword[type]))
|
|
|
- continue;
|
|
|
- return tomoyo_update_path2_acl(type, filename, filename2,
|
|
|
- domain, is_delete);
|
|
|
- }
|
|
|
- out:
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
|
|
|
*
|
|
@@ -866,13 +848,12 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
|
|
|
struct tomoyo_domain_info *const domain,
|
|
|
const bool is_delete)
|
|
|
{
|
|
|
- static const u32 tomoyo_rw_mask =
|
|
|
+ static const u16 tomoyo_rw_mask =
|
|
|
(1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
|
|
|
- const u32 perm = 1 << type;
|
|
|
+ const u16 perm = 1 << type;
|
|
|
struct tomoyo_acl_info *ptr;
|
|
|
struct tomoyo_path_acl e = {
|
|
|
.head.type = TOMOYO_TYPE_PATH_ACL,
|
|
|
- .perm_high = perm >> 16,
|
|
|
.perm = perm
|
|
|
};
|
|
|
int error = is_delete ? -ENOENT : -ENOMEM;
|
|
@@ -891,19 +872,13 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
|
|
|
if (!tomoyo_is_same_path_acl(acl, &e))
|
|
|
continue;
|
|
|
if (is_delete) {
|
|
|
- if (perm <= 0xFFFF)
|
|
|
- acl->perm &= ~perm;
|
|
|
- else
|
|
|
- acl->perm_high &= ~(perm >> 16);
|
|
|
+ acl->perm &= ~perm;
|
|
|
if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
|
|
|
acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
|
|
|
else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
|
|
|
acl->perm &= ~tomoyo_rw_mask;
|
|
|
} else {
|
|
|
- if (perm <= 0xFFFF)
|
|
|
- acl->perm |= perm;
|
|
|
- else
|
|
|
- acl->perm_high |= (perm >> 16);
|
|
|
+ acl->perm |= perm;
|
|
|
if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
|
|
|
acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
|
|
|
else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
|
|
@@ -927,6 +902,71 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list.
|
|
|
+ *
|
|
|
+ * @type: Type of operation.
|
|
|
+ * @filename: Filename.
|
|
|
+ * @mode: Create mode.
|
|
|
+ * @major: Device major number.
|
|
|
+ * @minor: Device minor number.
|
|
|
+ * @domain: Pointer to "struct tomoyo_domain_info".
|
|
|
+ * @is_delete: True if it is a delete request.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, negative value otherwise.
|
|
|
+ */
|
|
|
+static inline int tomoyo_update_path_number3_acl(const u8 type,
|
|
|
+ const char *filename,
|
|
|
+ char *mode,
|
|
|
+ char *major, char *minor,
|
|
|
+ struct tomoyo_domain_info *
|
|
|
+ const domain,
|
|
|
+ const bool is_delete)
|
|
|
+{
|
|
|
+ const u8 perm = 1 << type;
|
|
|
+ struct tomoyo_acl_info *ptr;
|
|
|
+ struct tomoyo_path_number3_acl e = {
|
|
|
+ .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL,
|
|
|
+ .perm = perm
|
|
|
+ };
|
|
|
+ int error = is_delete ? -ENOENT : -ENOMEM;
|
|
|
+ if (!tomoyo_parse_name_union(filename, &e.name) ||
|
|
|
+ !tomoyo_parse_number_union(mode, &e.mode) ||
|
|
|
+ !tomoyo_parse_number_union(major, &e.major) ||
|
|
|
+ !tomoyo_parse_number_union(minor, &e.minor))
|
|
|
+ goto out;
|
|
|
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
|
|
+ goto out;
|
|
|
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
|
|
|
+ struct tomoyo_path_number3_acl *acl =
|
|
|
+ container_of(ptr, struct tomoyo_path_number3_acl, head);
|
|
|
+ if (!tomoyo_is_same_path_number3_acl(acl, &e))
|
|
|
+ continue;
|
|
|
+ if (is_delete)
|
|
|
+ acl->perm &= ~perm;
|
|
|
+ else
|
|
|
+ acl->perm |= perm;
|
|
|
+ error = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!is_delete && error) {
|
|
|
+ struct tomoyo_path_number3_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);
|
|
|
+ out:
|
|
|
+ tomoyo_put_name_union(&e.name);
|
|
|
+ tomoyo_put_number_union(&e.mode);
|
|
|
+ tomoyo_put_number_union(&e.major);
|
|
|
+ tomoyo_put_number_union(&e.minor);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
|
|
|
*
|
|
@@ -988,6 +1028,50 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tomoyo_path_number3_acl - Check permission for path/number/number/number operation.
|
|
|
+ *
|
|
|
+ * @r: Pointer to "struct tomoyo_request_info".
|
|
|
+ * @filename: Filename to check.
|
|
|
+ * @perm: Permission.
|
|
|
+ * @mode: Create mode.
|
|
|
+ * @major: Device major number.
|
|
|
+ * @minor: Device minor number.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, -EPERM otherwise.
|
|
|
+ *
|
|
|
+ * Caller holds tomoyo_read_lock().
|
|
|
+ */
|
|
|
+static int tomoyo_path_number3_acl(struct tomoyo_request_info *r,
|
|
|
+ const struct tomoyo_path_info *filename,
|
|
|
+ const u16 perm, const unsigned int mode,
|
|
|
+ const unsigned int major,
|
|
|
+ const unsigned int minor)
|
|
|
+{
|
|
|
+ struct tomoyo_domain_info *domain = r->domain;
|
|
|
+ struct tomoyo_acl_info *ptr;
|
|
|
+ int error = -EPERM;
|
|
|
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
|
|
|
+ struct tomoyo_path_number3_acl *acl;
|
|
|
+ if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL)
|
|
|
+ continue;
|
|
|
+ acl = container_of(ptr, struct tomoyo_path_number3_acl, head);
|
|
|
+ if (!tomoyo_compare_number_union(mode, &acl->mode))
|
|
|
+ continue;
|
|
|
+ if (!tomoyo_compare_number_union(major, &acl->major))
|
|
|
+ continue;
|
|
|
+ if (!tomoyo_compare_number_union(minor, &acl->minor))
|
|
|
+ continue;
|
|
|
+ if (!(acl->perm & perm))
|
|
|
+ continue;
|
|
|
+ if (!tomoyo_compare_name_union(filename, &acl->name))
|
|
|
+ continue;
|
|
|
+ error = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tomoyo_path2_acl - Check permission for double path operation.
|
|
|
*
|
|
@@ -1068,6 +1152,195 @@ static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation.
|
|
|
+ *
|
|
|
+ * @r: Pointer to "struct tomoyo_request_info".
|
|
|
+ * @type: Operation.
|
|
|
+ * @filename: Filename to check.
|
|
|
+ * @number: Number.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, -EPERM otherwise.
|
|
|
+ *
|
|
|
+ * Caller holds tomoyo_read_lock().
|
|
|
+ */
|
|
|
+static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type,
|
|
|
+ const struct tomoyo_path_info *filename,
|
|
|
+ const unsigned long number)
|
|
|
+{
|
|
|
+ struct tomoyo_domain_info *domain = r->domain;
|
|
|
+ struct tomoyo_acl_info *ptr;
|
|
|
+ const u8 perm = 1 << type;
|
|
|
+ int error = -EPERM;
|
|
|
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
|
|
|
+ struct tomoyo_path_number_acl *acl;
|
|
|
+ if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL)
|
|
|
+ continue;
|
|
|
+ acl = container_of(ptr, struct tomoyo_path_number_acl,
|
|
|
+ head);
|
|
|
+ if (!(acl->perm & perm) ||
|
|
|
+ !tomoyo_compare_number_union(number, &acl->number) ||
|
|
|
+ !tomoyo_compare_name_union(filename, &acl->name))
|
|
|
+ continue;
|
|
|
+ error = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
|
|
|
+ *
|
|
|
+ * @type: Type of operation.
|
|
|
+ * @filename: Filename.
|
|
|
+ * @number: Number.
|
|
|
+ * @domain: Pointer to "struct tomoyo_domain_info".
|
|
|
+ * @is_delete: True if it is a delete request.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, negative value otherwise.
|
|
|
+ */
|
|
|
+static inline int tomoyo_update_path_number_acl(const u8 type,
|
|
|
+ const char *filename,
|
|
|
+ char *number,
|
|
|
+ struct tomoyo_domain_info *
|
|
|
+ const domain,
|
|
|
+ const bool is_delete)
|
|
|
+{
|
|
|
+ const u8 perm = 1 << type;
|
|
|
+ struct tomoyo_acl_info *ptr;
|
|
|
+ struct tomoyo_path_number_acl e = {
|
|
|
+ .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
|
|
|
+ .perm = perm
|
|
|
+ };
|
|
|
+ int error = is_delete ? -ENOENT : -ENOMEM;
|
|
|
+ if (!domain)
|
|
|
+ return -EINVAL;
|
|
|
+ if (!tomoyo_parse_name_union(filename, &e.name))
|
|
|
+ return -EINVAL;
|
|
|
+ if (!tomoyo_parse_number_union(number, &e.number))
|
|
|
+ goto out;
|
|
|
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
|
|
+ goto out;
|
|
|
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
|
|
|
+ struct tomoyo_path_number_acl *acl =
|
|
|
+ container_of(ptr, struct tomoyo_path_number_acl, head);
|
|
|
+ if (!tomoyo_is_same_path_number_acl(acl, &e))
|
|
|
+ continue;
|
|
|
+ if (is_delete)
|
|
|
+ acl->perm &= ~perm;
|
|
|
+ else
|
|
|
+ acl->perm |= perm;
|
|
|
+ error = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!is_delete && error) {
|
|
|
+ struct tomoyo_path_number_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);
|
|
|
+ out:
|
|
|
+ tomoyo_put_name_union(&e.name);
|
|
|
+ tomoyo_put_number_union(&e.number);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
|
|
|
+ *
|
|
|
+ * @r: Pointer to "strct tomoyo_request_info".
|
|
|
+ * @filename: Filename to check.
|
|
|
+ * @number: Number.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, negative value otherwise.
|
|
|
+ *
|
|
|
+ * Caller holds tomoyo_read_lock().
|
|
|
+ */
|
|
|
+static int tomoyo_path_number_perm2(struct tomoyo_request_info *r,
|
|
|
+ const u8 type,
|
|
|
+ const struct tomoyo_path_info *filename,
|
|
|
+ const unsigned long number)
|
|
|
+{
|
|
|
+ char buffer[64];
|
|
|
+ int error;
|
|
|
+ u8 radix;
|
|
|
+
|
|
|
+ if (!filename)
|
|
|
+ return 0;
|
|
|
+ switch (type) {
|
|
|
+ case TOMOYO_TYPE_CREATE:
|
|
|
+ case TOMOYO_TYPE_MKDIR:
|
|
|
+ case TOMOYO_TYPE_MKFIFO:
|
|
|
+ case TOMOYO_TYPE_MKSOCK:
|
|
|
+ case TOMOYO_TYPE_CHMOD:
|
|
|
+ radix = TOMOYO_VALUE_TYPE_OCTAL;
|
|
|
+ break;
|
|
|
+ case TOMOYO_TYPE_IOCTL:
|
|
|
+ radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ radix = TOMOYO_VALUE_TYPE_DECIMAL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ tomoyo_print_ulong(buffer, sizeof(buffer), number, radix);
|
|
|
+ error = tomoyo_path_number_acl(r, type, filename, number);
|
|
|
+ if (!error)
|
|
|
+ return 0;
|
|
|
+ tomoyo_warn_log(r, "%s %s %s", tomoyo_path_number2keyword(type),
|
|
|
+ filename->name, buffer);
|
|
|
+ if (tomoyo_domain_quota_is_ok(r))
|
|
|
+ tomoyo_update_path_number_acl(type,
|
|
|
+ tomoyo_get_file_pattern(filename)
|
|
|
+ ->name, buffer, r->domain, false);
|
|
|
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
|
|
|
+ error = 0;
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
|
|
|
+ *
|
|
|
+ * @type: Type of operation.
|
|
|
+ * @path: Pointer to "struct path".
|
|
|
+ * @number: Number.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, negative value otherwise.
|
|
|
+ */
|
|
|
+int tomoyo_path_number_perm(const u8 type, struct path *path,
|
|
|
+ unsigned long number)
|
|
|
+{
|
|
|
+ struct tomoyo_request_info r;
|
|
|
+ int error = -ENOMEM;
|
|
|
+ struct tomoyo_path_info *buf;
|
|
|
+ int idx;
|
|
|
+
|
|
|
+ if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
|
|
|
+ !path->mnt || !path->dentry)
|
|
|
+ return 0;
|
|
|
+ idx = tomoyo_read_lock();
|
|
|
+ buf = tomoyo_get_path(path);
|
|
|
+ if (!buf)
|
|
|
+ goto out;
|
|
|
+ if (type == TOMOYO_TYPE_MKDIR && !buf->is_dir) {
|
|
|
+ /*
|
|
|
+ * tomoyo_get_path() reserves space for appending "/."
|
|
|
+ */
|
|
|
+ strcat((char *) buf->name, "/");
|
|
|
+ tomoyo_fill_path_info(buf);
|
|
|
+ }
|
|
|
+ error = tomoyo_path_number_perm2(&r, type, buf, number);
|
|
|
+ out:
|
|
|
+ kfree(buf);
|
|
|
+ tomoyo_read_unlock(idx);
|
|
|
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
|
|
|
+ error = 0;
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tomoyo_check_exec_perm - Check permission for "execute".
|
|
|
*
|
|
@@ -1145,7 +1418,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "rewrite", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
|
|
|
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot", "mount" and "unmount".
|
|
|
*
|
|
|
* @operation: Type of operation.
|
|
|
* @path: Pointer to "struct path".
|
|
@@ -1173,7 +1446,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
|
|
|
goto out;
|
|
|
}
|
|
|
break;
|
|
|
- case TOMOYO_TYPE_MKDIR:
|
|
|
case TOMOYO_TYPE_RMDIR:
|
|
|
case TOMOYO_TYPE_CHROOT:
|
|
|
if (!buf->is_dir) {
|
|
@@ -1193,6 +1465,91 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation.
|
|
|
+ *
|
|
|
+ * @r: Pointer to "struct tomoyo_request_info".
|
|
|
+ * @operation: Type of operation.
|
|
|
+ * @filename: Filename to check.
|
|
|
+ * @mode: Create mode.
|
|
|
+ * @dev: Device number.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, negative value otherwise.
|
|
|
+ *
|
|
|
+ * Caller holds tomoyo_read_lock().
|
|
|
+ */
|
|
|
+static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r,
|
|
|
+ const u8 operation,
|
|
|
+ const struct tomoyo_path_info *filename,
|
|
|
+ const unsigned int mode,
|
|
|
+ const unsigned int dev)
|
|
|
+{
|
|
|
+ int error;
|
|
|
+ const unsigned int major = MAJOR(dev);
|
|
|
+ const unsigned int minor = MINOR(dev);
|
|
|
+
|
|
|
+ error = tomoyo_path_number3_acl(r, filename, 1 << operation, mode,
|
|
|
+ major, minor);
|
|
|
+ if (!error)
|
|
|
+ return 0;
|
|
|
+ tomoyo_warn_log(r, "%s %s 0%o %u %u",
|
|
|
+ tomoyo_path_number32keyword(operation),
|
|
|
+ filename->name, mode, major, minor);
|
|
|
+ if (tomoyo_domain_quota_is_ok(r)) {
|
|
|
+ char mode_buf[64];
|
|
|
+ char major_buf[64];
|
|
|
+ char minor_buf[64];
|
|
|
+ memset(mode_buf, 0, sizeof(mode_buf));
|
|
|
+ memset(major_buf, 0, sizeof(major_buf));
|
|
|
+ memset(minor_buf, 0, sizeof(minor_buf));
|
|
|
+ snprintf(mode_buf, sizeof(mode_buf) - 1, "0%o", mode);
|
|
|
+ snprintf(major_buf, sizeof(major_buf) - 1, "%u", major);
|
|
|
+ snprintf(minor_buf, sizeof(minor_buf) - 1, "%u", minor);
|
|
|
+ tomoyo_update_path_number3_acl(operation,
|
|
|
+ tomoyo_get_file_pattern(filename)
|
|
|
+ ->name, mode_buf, major_buf,
|
|
|
+ minor_buf, r->domain, false);
|
|
|
+ }
|
|
|
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
|
|
|
+ error = 0;
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar".
|
|
|
+ *
|
|
|
+ * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
|
|
|
+ * @path: Pointer to "struct path".
|
|
|
+ * @mode: Create mode.
|
|
|
+ * @dev: Device number.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, negative value otherwise.
|
|
|
+ */
|
|
|
+int tomoyo_path_number3_perm(const u8 operation, struct path *path,
|
|
|
+ const unsigned int mode, unsigned int dev)
|
|
|
+{
|
|
|
+ struct tomoyo_request_info r;
|
|
|
+ int error = -ENOMEM;
|
|
|
+ struct tomoyo_path_info *buf;
|
|
|
+ int idx;
|
|
|
+
|
|
|
+ if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
|
|
|
+ !path->mnt)
|
|
|
+ return 0;
|
|
|
+ idx = tomoyo_read_lock();
|
|
|
+ error = -ENOMEM;
|
|
|
+ buf = tomoyo_get_path(path);
|
|
|
+ if (buf) {
|
|
|
+ error = tomoyo_path_number3_perm2(&r, operation, buf, mode,
|
|
|
+ new_decode_dev(dev));
|
|
|
+ kfree(buf);
|
|
|
+ }
|
|
|
+ tomoyo_read_unlock(idx);
|
|
|
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
|
|
|
+ error = 0;
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
|
|
|
*
|
|
@@ -1254,3 +1611,60 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
|
|
|
error = 0;
|
|
|
return error;
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * tomoyo_write_file_policy - Update file related list.
|
|
|
+ *
|
|
|
+ * @data: String to parse.
|
|
|
+ * @domain: Pointer to "struct tomoyo_domain_info".
|
|
|
+ * @is_delete: True if it is a delete request.
|
|
|
+ *
|
|
|
+ * Returns 0 on success, negative value otherwise.
|
|
|
+ *
|
|
|
+ * Caller holds tomoyo_read_lock().
|
|
|
+ */
|
|
|
+int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
|
|
|
+ const bool is_delete)
|
|
|
+{
|
|
|
+ char *w[5];
|
|
|
+ u8 type;
|
|
|
+ if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
|
|
|
+ return -EINVAL;
|
|
|
+ if (strncmp(w[0], "allow_", 6)) {
|
|
|
+ unsigned int perm;
|
|
|
+ if (sscanf(w[0], "%u", &perm) == 1)
|
|
|
+ return tomoyo_update_file_acl((u8) perm, w[1], domain,
|
|
|
+ is_delete);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ w[0] += 6;
|
|
|
+ for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
|
|
|
+ if (strcmp(w[0], tomoyo_path_keyword[type]))
|
|
|
+ continue;
|
|
|
+ return tomoyo_update_path_acl(type, w[1], domain, is_delete);
|
|
|
+ }
|
|
|
+ if (!w[2][0])
|
|
|
+ goto out;
|
|
|
+ for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
|
|
|
+ if (strcmp(w[0], tomoyo_path2_keyword[type]))
|
|
|
+ continue;
|
|
|
+ return tomoyo_update_path2_acl(type, w[1], w[2], domain,
|
|
|
+ is_delete);
|
|
|
+ }
|
|
|
+ for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
|
|
|
+ if (strcmp(w[0], tomoyo_path_number_keyword[type]))
|
|
|
+ continue;
|
|
|
+ return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
|
|
|
+ is_delete);
|
|
|
+ }
|
|
|
+ if (!w[3][0] || !w[4][0])
|
|
|
+ goto out;
|
|
|
+ for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) {
|
|
|
+ if (strcmp(w[0], tomoyo_path_number3_keyword[type]))
|
|
|
+ continue;
|
|
|
+ return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3],
|
|
|
+ w[4], domain, is_delete);
|
|
|
+ }
|
|
|
+ out:
|
|
|
+ return -EINVAL;
|
|
|
+}
|