/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle (ignored) * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * miscdevfs packet format: * Octet 0: Type * Octets 1-4: network byte order msg_ctx->counter (0's for non-response) * Octets 5-N0: Size of struct ecryptfs_message to follow * Octets N0-N1: struct ecryptfs_message (including data) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length, i; ssize_t sz = 0; char *data; uid_t euid = current_euid(); unsigned char packet_size_peek[3]; int rc; if (count == 0) { goto out; } else if (count == (1 + 4)) { /* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */ goto memdup; } else if (count < (1 + 4 + 1) || count > (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)) { printk(KERN_WARNING "%s: Acceptable packet size range is " "[%d-%lu], but amount of data written is [%zu].", __func__, (1 + 4 + 1), (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES), count); return -EINVAL; } if (copy_from_user(packet_size_peek, (buf + 1 + 4), sizeof(packet_size_peek))) { printk(KERN_WARNING "%s: Error while inspecting packet size\n", __func__); return -EFAULT; } rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%d]\n", __func__, rc); return rc; } if ((1 + 4 + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__, packet_size); return -EINVAL; } memdup: data = memdup_user(buf, count); if (IS_ERR(data)) { printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", __func__, PTR_ERR(data)); goto out; } sz = count; i = 0; switch (data[i++]) { case ECRYPTFS_MSG_RESPONSE: if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%zd], but amount of data written is " "only [%zd]. Discarding response packet.\n", __func__, (1 + 4 + 1 + sizeof(struct ecryptfs_message)), count); goto out_free; } memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); i += 4 + packet_size_length; rc = ecryptfs_miscdev_response(&data[i], packet_size, euid, current_user_ns(), task_pid(current), seq); if (rc) printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%d]\n", __func__, rc); break; case ECRYPTFS_MSG_HELO: case ECRYPTFS_MSG_QUIT: break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); break; } out_free: kfree(data); out: return sz; }
/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle (ignored) * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * miscdevfs packet format: * Octet 0: Type * Octets 1-4: network byte order msg_ctx->counter (0's for non-response) * Octets 5-N0: Size of struct ecryptfs_message to follow * Octets N0-N1: struct ecryptfs_message (including data) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length, i; ssize_t sz = 0; char *data; int rc; if (count == 0) goto out; data = kmalloc(count, GFP_KERNEL); if (!data) { printk(KERN_ERR "%s: Out of memory whilst attempting to " "kmalloc([%Zd], GFP_KERNEL)\n", __func__, count); goto out; } rc = copy_from_user(data, buf, count); if (rc) { printk(KERN_ERR "%s: copy_from_user returned error [%d]\n", __func__, rc); goto out_free; } sz = count; i = 0; switch (data[i++]) { case ECRYPTFS_MSG_RESPONSE: if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%Zd], but amount of data written is " "only [%Zd]. Discarding response packet.\n", __func__, (1 + 4 + 1 + sizeof(struct ecryptfs_message)), count); goto out_free; } memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); i += 4; rc = ecryptfs_parse_packet_length(&data[i], &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%d]\n", __func__, rc); goto out_free; } i += packet_size_length; if ((1 + 4 + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: (1 + packet_size_length([%Zd])" " + packet_size([%Zd]))([%Zd]) != " "count([%Zd]). Invalid packet format.\n", __func__, packet_size_length, packet_size, (1 + packet_size_length + packet_size), count); goto out_free; } rc = ecryptfs_miscdev_response(&data[i], packet_size, current->euid, current->nsproxy->user_ns, task_pid(current), seq); if (rc) printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%d]\n", __func__, rc); break; case ECRYPTFS_MSG_HELO: rc = ecryptfs_miscdev_helo(current->euid, current->nsproxy->user_ns, task_pid(current)); if (rc) { printk(KERN_ERR "%s: Error attempting to process " "helo from pid [0x%p]; rc = [%d]\n", __func__, task_pid(current), rc); goto out_free; } break; case ECRYPTFS_MSG_QUIT: rc = ecryptfs_miscdev_quit(current->euid, current->nsproxy->user_ns, task_pid(current)); if (rc) { printk(KERN_ERR "%s: Error attempting to process " "quit from pid [0x%p]; rc = [%d]\n", __func__, task_pid(current), rc); goto out_free; } break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); break; } out_free: kfree(data); out: return sz; }
/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle (ignored) * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * miscdevfs packet format: * Octet 0: Type * Octets 1-4: network byte order msg_ctx->counter (0's for non-response) * Octets 5-N0: Size of struct ecryptfs_message to follow * Octets N0-N1: struct ecryptfs_message (including data) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length, i; ssize_t sz = 0; char *data; uid_t euid = current_euid(); int rc; if (count == 0) goto out; data = memdup_user(buf, count); if (IS_ERR(data)) { printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", __func__, PTR_ERR(data)); goto out; } sz = count; i = 0; switch (data[i++]) { case ECRYPTFS_MSG_RESPONSE: if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%zd], but amount of data written is " "only [%zd]. Discarding response packet.\n", __func__, (1 + 4 + 1 + sizeof(struct ecryptfs_message)), count); goto out_free; } memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); i += 4; rc = ecryptfs_parse_packet_length(&data[i], &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%d]\n", __func__, rc); goto out_free; } i += packet_size_length; if ((1 + 4 + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: (1 + packet_size_length([%zd])" " + packet_size([%zd]))([%zd]) != " "count([%zd]). Invalid packet format.\n", __func__, packet_size_length, packet_size, (1 + packet_size_length + packet_size), count); goto out_free; } rc = ecryptfs_miscdev_response(&data[i], packet_size, euid, current_user_ns(), task_pid(current), seq); if (rc) printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%d]\n", __func__, rc); break; case ECRYPTFS_MSG_CLEARMASTER_BLACK: printk(KERN_DEBUG "Clear the master key with blacklist"); break; case ECRYPTFS_MSG_HELO: case ECRYPTFS_MSG_QUIT: break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); break; } out_free: kfree(data); out: return sz; }
int parse_packet(struct ecryptfs_ctx *ctx, struct ecryptfs_message *emsg, struct ecryptfs_message **reply) { struct ecryptfs_auth_tok *auth_tok = NULL; size_t i = 0; size_t data_size; size_t key_size; size_t length_size; size_t key_out_size; unsigned char *signature = NULL; unsigned char packet_type; char *key = NULL; char *key_out = NULL; key_serial_t key_sub; int rc; packet_type = emsg->data[i++]; if ((rc = ecryptfs_parse_packet_length(&emsg->data[i], &data_size, &length_size))) { syslog(LOG_ERR, "Invalid packet format\n"); goto write_failure; } i += length_size; signature = malloc(data_size + 1); if (!signature) { rc = -errno; syslog(LOG_ERR, "Failed to allocate memory: %m\n"); goto write_failure; } memcpy(signature, &emsg->data[i], data_size); signature[data_size] = '\0'; i += data_size; rc = ecryptfs_parse_packet_length(&emsg->data[i], &key_size, &length_size); if (rc) { syslog(LOG_ERR, "Invalid packet format\n"); goto write_failure; } i += length_size; if ((key = malloc(key_size)) == NULL) { rc = -ENOMEM; syslog(LOG_ERR, "Failed to allocate memory\n"); goto write_failure; } memcpy(key, &emsg->data[i], key_size); i += key_size; key_sub = request_key("user", (char *)signature, NULL, KEY_SPEC_USER_KEYRING); if (key_sub < 0) { syslog(LOG_ERR, "Could not find key with signature: " "[%s]\n", signature); rc = -EINVAL; goto write_failure; } rc = keyctl_read_alloc(key_sub, (void **)(&auth_tok)); switch (packet_type) { case ECRYPTFS_TAG_64_PACKET: if ((rc = key_mod_decrypt(&key_out, &key_out_size, ctx, auth_tok, key, key_size))) { syslog(LOG_ERR, "Failed to decrypt key; rc = [%d]\n", rc); rc = write_failure_packet(ECRYPTFS_TAG_65_PACKET, reply); goto write_failure; } if ((rc = write_tag_65_packet((unsigned char *)key_out, key_out_size, reply))) { syslog(LOG_ERR, "Failed to write decrypted " "key via tag 65 packet\n"); goto write_failure; } break; case ECRYPTFS_TAG_66_PACKET: rc = key_mod_encrypt(&key_out, &key_out_size, ctx, auth_tok, key, key_size); if (rc) { syslog(LOG_ERR, "Failed to encrypt public " "key\n"); goto write_failure; } rc = write_tag_67_packet(key_out, key_out_size, reply); if (rc) { syslog(LOG_ERR, "Failed to write encrypted " "key to tag 67 packet\n"); goto write_failure; } break; default: syslog(LOG_ERR, "Unrecognized packet type: [%d]\n", packet_type); rc = -EINVAL; break; } free(key); free(signature); free(key_out); memset(auth_tok, 0, (sizeof(struct ecryptfs_auth_tok) + auth_tok->token.private_key.data_len)); free(auth_tok); return rc; write_failure: if(packet_type == ECRYPTFS_TAG_66_PACKET) rc = write_failure_packet(ECRYPTFS_TAG_67_PACKET, reply); else rc = write_failure_packet(ECRYPTFS_TAG_65_PACKET, reply); free(key); free(signature); free(key_out); if (auth_tok) { memset(auth_tok, 0, (sizeof(struct ecryptfs_auth_tok) + auth_tok->token.private_key.data_len)); free(auth_tok); } return rc; }
/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length; char *data; unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE]; ssize_t rc; if (count == 0) { return 0; } else if (count == MIN_NON_MSG_PKT_SIZE) { /* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */ goto memdup; } else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) { printk(KERN_WARNING "%s: Acceptable packet size range is " "[%d-%zu], but amount of data written is [%zu].", __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count); return -EINVAL; } if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET], sizeof(packet_size_peek))) { printk(KERN_WARNING "%s: Error while inspecting packet size\n", __func__); return -EFAULT; } rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%zd]\n", __func__, rc); return rc; } if ((PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__, packet_size); return -EINVAL; } memdup: data = memdup_user(buf, count); if (IS_ERR(data)) { printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", __func__, PTR_ERR(data)); return PTR_ERR(data); } switch (data[PKT_TYPE_OFFSET]) { case ECRYPTFS_MSG_RESPONSE: if (count < (MIN_MSG_PKT_SIZE + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%zd], but amount of data written is " "only [%zd]. Discarding response packet.\n", __func__, (MIN_MSG_PKT_SIZE + sizeof(struct ecryptfs_message)), count); rc = -EINVAL; goto out_free; } memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE); seq = be32_to_cpu(counter_nbo); rc = ecryptfs_miscdev_response(file->private_data, &data[PKT_LEN_OFFSET + packet_size_length], packet_size, seq); if (rc) { printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%zd]\n", __func__, rc); goto out_free; } break; case ECRYPTFS_MSG_HELO: case ECRYPTFS_MSG_QUIT: break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); rc = -EINVAL; goto out_free; } rc = count; out_free: kfree(data); return rc; }