diff --git a/fs/hmdfs/comm/connection.c b/fs/hmdfs/comm/connection.c index 51e6f829eb343b7bc929b899d5d2243cfe31ba49..5a2e5b0f5b027cdb942bf458f8575f280e7afd26 100644 --- a/fs/hmdfs/comm/connection.c +++ b/fs/hmdfs/comm/connection.c @@ -1092,9 +1092,8 @@ static struct hmdfs_peer *add_peer_unsafe(struct hmdfs_sb_info *sbi, return peer2add; } -static struct hmdfs_peer * -alloc_peer(struct hmdfs_sb_info *sbi, uint8_t *cid, - const struct connection_operations *conn_operations) +static struct hmdfs_peer *alloc_peer(struct hmdfs_sb_info *sbi, uint8_t *cid, + const struct connection_operations *conn_operations, uint32_t devsl) { struct hmdfs_peer *node = kzalloc(sizeof(*node), GFP_KERNEL); @@ -1178,6 +1177,7 @@ alloc_peer(struct hmdfs_sb_info *sbi, uint8_t *cid, init_waitqueue_head(&node->rebuild_inode_status_wq); INIT_LIST_HEAD(&node->stashed_inode_list); node->need_rebuild_stash_list = false; + node->devsl = devsl; return node; @@ -1206,7 +1206,8 @@ alloc_peer(struct hmdfs_sb_info *sbi, uint8_t *cid, return NULL; } -struct hmdfs_peer *hmdfs_get_peer(struct hmdfs_sb_info *sbi, uint8_t *cid) +struct hmdfs_peer *hmdfs_get_peer(struct hmdfs_sb_info *sbi, uint8_t *cid, + uint32_t devsl) { struct hmdfs_peer *peer = NULL, *on_sbi_peer = NULL; const struct connection_operations *conn_opr_ptr = NULL; @@ -1225,7 +1226,7 @@ struct hmdfs_peer *hmdfs_get_peer(struct hmdfs_sb_info *sbi, uint8_t *cid) hmdfs_info("Fatal! Cannot get peer operation"); goto out; } - peer = alloc_peer(sbi, cid, conn_opr_ptr); + peer = alloc_peer(sbi, cid, conn_opr_ptr, devsl); if (unlikely(!peer)) { hmdfs_info("Failed to alloc a peer"); goto out; diff --git a/fs/hmdfs/comm/connection.h b/fs/hmdfs/comm/connection.h index 6f3ee1baddf2177a5d9714a5ed1a8b419c73ae11..2d80491b9201438f401f7c4d17dc477e21359faa 100644 --- a/fs/hmdfs/comm/connection.h +++ b/fs/hmdfs/comm/connection.h @@ -213,6 +213,7 @@ struct hmdfs_peer { /* sysfs */ struct kobject kobj; struct completion kobj_unregister; + uint32_t devsl; }; #define HMDFS_DEVID_LOCAL 0 @@ -297,7 +298,8 @@ struct connection *get_conn_impl(struct hmdfs_peer *node, int connect_type); void set_conn_sock_quickack(struct hmdfs_peer *node); -struct hmdfs_peer *hmdfs_get_peer(struct hmdfs_sb_info *sbi, uint8_t *cid); +struct hmdfs_peer *hmdfs_get_peer(struct hmdfs_sb_info *sbi, uint8_t *cid, + uint32_t devsl); struct hmdfs_peer *hmdfs_lookup_from_devid(struct hmdfs_sb_info *sbi, uint64_t device_id); diff --git a/fs/hmdfs/comm/device_node.c b/fs/hmdfs/comm/device_node.c index 183f3b7172c522b8b5142de151ff25c4d0d6f40c..c6bf560864008355f2c0cfa65f4e046d046302b9 100644 --- a/fs/hmdfs/comm/device_node.c +++ b/fs/hmdfs/comm/device_node.c @@ -48,7 +48,7 @@ static void ctrl_cmd_update_socket_handler(const char *buf, size_t len, } memcpy(&cmd, buf, sizeof(cmd)); - node = hmdfs_get_peer(sbi, cmd.cid); + node = hmdfs_get_peer(sbi, cmd.cid, cmd.devsl); if (unlikely(!node)) { hmdfs_err("failed to update ctrl node: cannot get peer"); goto out; @@ -72,6 +72,28 @@ static void ctrl_cmd_update_socket_handler(const char *buf, size_t len, peer_put(node); } +static void ctrl_cmd_update_devsl_handler(const char *buf, size_t len, + struct hmdfs_sb_info *sbi) +{ + struct update_devsl_param cmd; + struct hmdfs_peer *node = NULL; + + if (unlikely(!buf || len != sizeof(cmd))) { + hmdfs_err("Recved a invalid userbuf"); + return; + } + memcpy(&cmd, buf, sizeof(cmd)); + + node = hmdfs_lookup_from_cid(sbi, cmd.cid); + if (unlikely(!node)) { + hmdfs_err("failed to update devsl: cannot get peer"); + return; + } + hmdfs_info("Found peer: device_id = %llu", node->device_id); + node->devsl = cmd.devsl; + peer_put(node); +} + static inline void hmdfs_disconnect_node_marked(struct hmdfs_peer *conn) { hmdfs_start_process_offline(conn); @@ -152,6 +174,7 @@ typedef void (*ctrl_cmd_handler)(const char *buf, size_t len, static const ctrl_cmd_handler cmd_handler[CMD_CNT] = { [CMD_UPDATE_SOCKET] = ctrl_cmd_update_socket_handler, + [CMD_UPDATE_DEVSL] = ctrl_cmd_update_devsl_handler, [CMD_OFF_LINE] = ctrl_cmd_off_line_handler, [CMD_OFF_LINE_ALL] = ctrl_cmd_off_line_all_handler, }; @@ -179,8 +202,10 @@ static const char *cmd2str(int cmd) case 0: return "CMD_UPDATE_SOCKET"; case 1: - return "CMD_OFF_LINE"; + return "CMD_UPDATE_DEVSL"; case 2: + return "CMD_OFF_LINE"; + case 3: return "CMD_OFF_LINE_ALL"; default: return "illegal cmd"; diff --git a/fs/hmdfs/comm/device_node.h b/fs/hmdfs/comm/device_node.h index 3c99c7fb679fbe723deb4c56e77a52d115992969..fdc64d467287f93776e3a488db9e47217d5b055d 100644 --- a/fs/hmdfs/comm/device_node.h +++ b/fs/hmdfs/comm/device_node.h @@ -13,6 +13,7 @@ enum CTRL_NODE_CMD { CMD_UPDATE_SOCKET = 0, + CMD_UPDATE_DEVSL, CMD_OFF_LINE, CMD_OFF_LINE_ALL, CMD_CNT, @@ -21,11 +22,18 @@ enum CTRL_NODE_CMD { struct update_socket_param { int32_t cmd; int32_t newfd; + uint32_t devsl; uint8_t status; uint8_t masterkey[HMDFS_KEY_SIZE]; uint8_t cid[HMDFS_CID_SIZE]; } __packed; +struct update_devsl_param { + int32_t cmd; + uint32_t devsl; + uint8_t cid[HMDFS_CID_SIZE]; +} __attribute__((packed)); + struct offline_param { int32_t cmd; uint8_t remote_cid[HMDFS_CID_SIZE]; diff --git a/fs/hmdfs/hmdfs_server.c b/fs/hmdfs/hmdfs_server.c index c50e9f9de8429aac4ba3a9944e2f7be486cd83ef..4da2fc70c1a5fc237c74b38c7e8ef3545bff9a63 100644 --- a/fs/hmdfs/hmdfs_server.c +++ b/fs/hmdfs/hmdfs_server.c @@ -220,6 +220,74 @@ static int hmdfs_get_inode_by_name(struct hmdfs_peer *con, const char *filename, return 0; } +static const char *datasl_str[] = { + "s0", "s1", "s2", "s3", "s4" +}; + +static int parse_data_sec_level(const char *sl_value, size_t sl_value_len) +{ + int i; + + for (i = 0; i <= sizeof(datasl_str) / sizeof(datasl_str[0]); i++) { + if (!strncmp(sl_value, datasl_str[i], strlen(datasl_str[i]))) + return i + DATA_SEC_LEVEL0; + } + + return DATA_SEC_LEVEL3; +} + +static int check_sec_level(struct hmdfs_peer *node, const char *file_name) +{ + int err; + int ret = 0; + struct path root_path; + struct path file_path; + char *value; + size_t value_len = DATA_SEC_LEVEL_LENGTH; + + if (node->devsl <= 0) { + ret = -EACCES; + goto out_free; + } + + value = kzalloc(value_len, GFP_KERNEL); + if (!value) { + ret = -ENOMEM; + goto out_free; + } + + err = kern_path(node->sbi->local_dst, LOOKUP_DIRECTORY, &root_path); + if (err) { + hmdfs_err("get root path error"); + ret = err; + goto out_free; + } + + err = vfs_path_lookup(root_path.dentry, root_path.mnt, file_name, 0, + &file_path); + if (err) { + hmdfs_err("get file path error"); + ret = err; + goto out_err; + } + + err = vfs_getxattr(file_path.dentry, DATA_SEC_LEVEL_LABEL, value, + value_len); + if (err <= 0 && node->devsl >= DATA_SEC_LEVEL3) + goto out; + if (err > 0 && node->devsl >= parse_data_sec_level(value, err)) + goto out; + + ret = -EACCES; +out: + path_put(&file_path); +out_err: + path_put(&root_path); +out_free: + kfree(value); + return ret; +} + static struct file *hmdfs_open_file(struct hmdfs_peer *con, const char *filename, uint8_t file_type, int *file_id) @@ -232,6 +300,11 @@ static struct file *hmdfs_open_file(struct hmdfs_peer *con, return ERR_PTR(-EINVAL); } + if (check_sec_level(con, filename)) { + hmdfs_err("devsl permission denied"); + return ERR_PTR(-EACCES); + } + if (hm_islnk(file_type)) file = hmdfs_open_photokit_path(con->sbi, filename); else diff --git a/fs/hmdfs/hmdfs_server.h b/fs/hmdfs/hmdfs_server.h index 844f3a9ee82c41ad1ab0b7e3c5f01905006cf85d..740d06f8b3a5bf659f113e3ad765cb2ad61994d2 100644 --- a/fs/hmdfs/hmdfs_server.h +++ b/fs/hmdfs/hmdfs_server.h @@ -12,6 +12,14 @@ #include "comm/transport.h" #include "comm/socket_adapter.h" +#define DATA_SEC_LEVEL0 0 +#define DATA_SEC_LEVEL1 1 +#define DATA_SEC_LEVEL2 2 +#define DATA_SEC_LEVEL3 3 +#define DATA_SEC_LEVEL4 4 +#define DATA_SEC_LEVEL_LABEL "user.security" +#define DATA_SEC_LEVEL_LENGTH 10 + static inline void hmdfs_send_err_response(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, int err) {