Example #1
0
/**
 * 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;
}
Example #2
0
/**
 * 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;
}
Example #3
0
/**
 * 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;
}
Example #4
0
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;
}
Example #5
0
/**
 * 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;
}