blob: 43025b02d13a7429cd8043de4a496e3669cf1ff2 [file] [log] [blame]
/*
* sdp_ioctl.c
*
*/
#include <linux/uaccess.h>
#include "../fscrypt_private.h"
int fscrypt_sdp_ioctl_get_sdp_info(struct inode *inode, unsigned long arg)
{
struct dek_arg_sdp_info req;
struct fscrypt_info *ci;
int result = 0;
if (inode->i_crypt_info == NULL) {
DEK_LOGE("No encryption context to the target..\n");
return -EOPNOTSUPP;
}
memset(&req, 0, sizeof(struct dek_arg_sdp_info));
req.engine_id = -1;
req.type = -1;
req.sdp_enabled = 1;
ci = inode->i_crypt_info;
if(!ci->ci_sdp_info) {
DEK_LOGE("get_info: can't find sdp info\n");
} else {
DEK_LOGD("get_info: ci->i_crypt_info->sdp_flags: 0x%08x\n",
ci->ci_sdp_info->sdp_flags);
if (ci->ci_sdp_info->sdp_flags & SDP_DEK_IS_SENSITIVE) {
req.is_sensitive = 1;
req.engine_id = ci->ci_sdp_info->engine_id;
req.type = ci->ci_sdp_info->sdp_dek.type;
}
if (ci->ci_sdp_info->sdp_flags & SDP_IS_CHAMBER_DIR)
req.is_chamber = 1;
}
if (copy_to_user((void __user *)arg, &req, sizeof(req))) {
DEK_LOGE("get_info: failed to copy data to user\n");
result = -EFAULT;
}
return result;
}
int fscrypt_sdp_ioctl_set_sdp_policy(struct inode *inode, unsigned long arg)
{
dek_arg_set_sdp_policy_t req;
int rc = 0;
if (inode->i_crypt_info == NULL) {
DEK_LOGE("no encryption context to the target..\n");
rc = -EOPNOTSUPP;
} else {
if (!is_root()) {
DEK_LOGE("set_policy: operation not permitted to non-root process\n");
return -EPERM;
}
memset(&req, 0, sizeof(dek_arg_set_sdp_policy_t));
if (copy_from_user(&req,
(dek_arg_set_sdp_policy_t __user *)arg, sizeof(req))) {
DEK_LOGE("set_policy: failed to copy data from user\n");
return -EFAULT;
}
rc = fscrypt_sdp_set_sdp_policy(inode, req.engine_id);
if (rc) {
DEK_LOGE("set_policy: operation failed (err:%d)\n", rc);
rc = -EFAULT;
}
}
return rc;
}
int fscrypt_sdp_ioctl_set_sensitive(struct inode *inode, unsigned long arg)
{
dek_arg_set_sensitive_t req;
int result = 0;
if (inode->i_crypt_info == NULL) {
DEK_LOGE("No encryption context to the target..\n");
result = -EOPNOTSUPP;
} else {
struct fscrypt_info *ci = inode->i_crypt_info;
if (ci->ci_sdp_info &&
(ci->ci_sdp_info->sdp_flags & SDP_DEK_IS_SENSITIVE)) {
DEK_LOGE("already sensitive file\n");
return 0;
}
if (S_ISDIR(inode->i_mode) && !is_root()) {
#ifdef CONFIG_SDP_KEY_DUMP
if (get_sdp_sysfs_key_dump()) {
DEK_LOGD("Temporarily allowed to process not vold.");
} else {
#endif
DEK_LOGE("Only vold as root process can set sensitive directory\n");
return -EPERM;
#ifdef CONFIG_SDP_KEY_DUMP
}
#endif
}
memset(&req, 0, sizeof(dek_arg_set_sensitive_t));
if (copy_from_user(&req,
(dek_arg_set_sensitive_t __user *)arg, sizeof(req))) {
DEK_LOGE("can't copy from user\n");
memset(&req, 0, sizeof(dek_arg_set_sensitive_t));
result = -EFAULT;
} else {
int rc = fscrypt_sdp_set_sensitive(inode, req.engine_id, NULL);
if (rc) {
DEK_LOGE("failed to set sensitive rc(%d)\n", rc);
memset(&req, 0, sizeof(dek_arg_set_sensitive_t));
return -EFAULT;
}
memset(&req, 0, sizeof(dek_arg_set_sensitive_t));
}
}
return result;
}
int fscrypt_sdp_ioctl_set_protected(struct inode *inode, unsigned long arg)
{
dek_arg_set_protected_t req;
int result = 0;
if (inode->i_crypt_info == NULL) {
DEK_LOGE("No encryption context to the target..\n");
result = -EOPNOTSUPP;
} else {
int rc;
if (S_ISDIR(inode->i_mode) && !is_root()) {
#ifdef CONFIG_SDP_KEY_DUMP
if (get_sdp_sysfs_key_dump()) {
DEK_LOGD("Temporarily allowed to process not vold.");
} else {
#endif
DEK_LOGE("Only vold as root process can set protected directory\n");
return -EPERM;
#ifdef CONFIG_SDP_KEY_DUMP
}
#endif
}
memset(&req, 0, sizeof(dek_arg_set_protected_t));
if (copy_from_user(&req,
(dek_arg_set_protected_t __user *)arg, sizeof(req))) {
DEK_LOGE("set_protected: failed to copy data from user\n");
return -EFAULT;
}
rc = fscrypt_sdp_set_protected(inode, req.engine_id);
if (rc) {
DEK_LOGE("failed to set protected rc(%d)\n", rc);
result = -EFAULT;
}
}
return result;
}
int fscrypt_sdp_ioctl_add_chamber_directory(struct inode *inode, unsigned long arg)
{
int result = 0;
if (inode->i_crypt_info == NULL) {
DEK_LOGE("No encryption context to the target..\n");
result = -EOPNOTSUPP;
} else {
dek_arg_add_chamber_t req;
struct fscrypt_info *ci = inode->i_crypt_info;
if (!S_ISDIR(inode->i_mode)) {
DEK_LOGE("Not directory\n");
return -EOPNOTSUPP;
}
if (ci->ci_sdp_info &&
ci->ci_sdp_info->sdp_flags & SDP_IS_CHAMBER_DIR) {
DEK_LOGE("Already chamber directory\n");
return 0;
}
if (!is_root()) {
DEK_LOGE("Permission denied: only epm process can call this\n");
return -EPERM;
}
memset(&req, 0, sizeof(dek_arg_add_chamber_t));
if (copy_from_user(&req,
(dek_arg_add_chamber_t __user *)arg, sizeof(req))) {
DEK_LOGE("can't copy from user\n");
memset(&req, 0, sizeof(dek_arg_add_chamber_t));
result = -EFAULT;
} else {
int rc = fscrypt_sdp_add_chamber_directory(req.engine_id, inode);
if (rc) {
DEK_LOGE("failed to add chamber rc(%d)\n", rc);
memset(&req, 0, sizeof(dek_arg_add_chamber_t));
return -EFAULT;
}
memset(&req, 0, sizeof(dek_arg_add_chamber_t));
}
}
return result;
}
int fscrypt_sdp_ioctl_remove_chamber_directory(struct inode *inode)
{
int result = 0;
if (inode->i_crypt_info == NULL) {
DEK_LOGE("No encryption context to the target..\n");
result = -EOPNOTSUPP;
} else {
int rc;
struct fscrypt_info *ci = inode->i_crypt_info;
if (!ci->ci_sdp_info ||
!(ci->ci_sdp_info->sdp_flags & SDP_IS_CHAMBER_DIR)) {
DEK_LOGE("Not chamber directory\n");
return 0;
}
if (!is_root()) {
DEK_LOGE("Permission denied: only epm process can call this\n");
return -EPERM;
}
rc = fscrypt_sdp_remove_chamber_directory(inode);
if (rc) {
DEK_LOGE("failed to remove chamber rc(%d)\n", rc);
result = -EFAULT;
}
}
return result;
}
int fscrypt_sdp_ioctl_dump_file_key(struct inode *inode)
{
#ifdef CONFIG_SDP_KEY_DUMP
int rc = 0;
DEK_LOGE("%s(ino:%ld)\n", __func__, inode->i_ino);
if (inode->i_crypt_info == NULL) {
DEK_LOGE("no encryption context to the target..\n");
rc = -EOPNOTSUPP;
} else {
rc = fscrypt_sdp_dump_file_key(inode);
if (rc) {
DEK_LOGE("dump_file_key: operation failed (err:%d)\n", rc);
rc = -EFAULT;
}
}
return rc;
#else
return 0;
#endif
}
/*
* -ENOTTY will be returned if this ioctl is not related to SDP
*/
int fscrypt_sdp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file_inode(filp);
if (!fscrypt_has_encryption_key(inode)) {
//Not allowed without i_crypt_info, go to the default ioctl
return -ENOTTY;
}
switch (cmd) {
case FS_IOC_GET_SDP_INFO:
return fscrypt_sdp_ioctl_get_sdp_info(inode, arg);
case FS_IOC_SET_SDP_POLICY:
return fscrypt_sdp_ioctl_set_sdp_policy(inode, arg);
case FS_IOC_SET_SENSITIVE:
return fscrypt_sdp_ioctl_set_sensitive(inode, arg);
case FS_IOC_SET_PROTECTED:
return fscrypt_sdp_ioctl_set_protected(inode, arg);
case FS_IOC_ADD_CHAMBER:
return fscrypt_sdp_ioctl_add_chamber_directory(inode, arg);
case FS_IOC_REMOVE_CHAMBER:
return fscrypt_sdp_ioctl_remove_chamber_directory(inode);
case FS_IOC_DUMP_FILE_KEY:
return fscrypt_sdp_ioctl_dump_file_key(inode);
default:
return -ENOTTY;
}
}