271 lines
6.7 KiB
C
Executable File
271 lines
6.7 KiB
C
Executable File
/*
|
|
* 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;
|
|
}
|
|
|
|
/*
|
|
* -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);
|
|
default:
|
|
return -ENOTTY;
|
|
}
|
|
}
|