Commit b6102813 authored by Connor Kuehl's avatar Connor Kuehl Committed by Herbert Xu

crypto: ccp - use file mode for sev ioctl permissions

Instead of using CAP_SYS_ADMIN which is restricted to the root user,
check the file mode for write permissions before executing commands that
can affect the platform. This allows for more fine-grained access
control to the SEV ioctl interface. This would allow a SEV-only user
or group the ability to administer the platform without requiring them
to be root or granting them overly powerful permissions.

For example:

chown root:root /dev/sev
chmod 600 /dev/sev
setfacl -m g:sev:r /dev/sev
setfacl -m g:sev-admin:rw /dev/sev

In this instance, members of the "sev-admin" group have the ability to
perform all ioctl calls (including the ones that modify platform state).
Members of the "sev" group only have access to the ioctls that do not
modify the platform state.

This also makes opening "/dev/sev" more consistent with how file
descriptors are usually handled. By only checking for CAP_SYS_ADMIN,
the file descriptor could be opened read-only but could still execute
ioctls that modify the platform state. This patch enforces that the file
descriptor is opened with write privileges if it is going to be used to
modify the platform state.

This flexibility is completely opt-in, and if it is not desirable by
the administrator then they do not need to give anyone else access to
/dev/sev.
Signed-off-by: default avatarConnor Kuehl <ckuehl@redhat.com>
Reviewed-by: default avatarBrijesh Singh <brijesh.singh@amd.com>
Reviewed-by: default avatarBandan Das <bsd@redhat.com>
Acked-by: default avatarDavid Rientjes <rientjes@google.com>
Acked-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent f086fd1e
...@@ -283,11 +283,11 @@ static int sev_get_platform_state(int *state, int *error) ...@@ -283,11 +283,11 @@ static int sev_get_platform_state(int *state, int *error)
return rc; return rc;
} }
static int sev_ioctl_do_reset(struct sev_issue_cmd *argp) static int sev_ioctl_do_reset(struct sev_issue_cmd *argp, bool writable)
{ {
int state, rc; int state, rc;
if (!capable(CAP_SYS_ADMIN)) if (!writable)
return -EPERM; return -EPERM;
/* /*
...@@ -331,12 +331,12 @@ static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) ...@@ -331,12 +331,12 @@ static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)
return ret; return ret;
} }
static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp) static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
int rc; int rc;
if (!capable(CAP_SYS_ADMIN)) if (!writable)
return -EPERM; return -EPERM;
if (sev->state == SEV_STATE_UNINIT) { if (sev->state == SEV_STATE_UNINIT) {
...@@ -348,7 +348,7 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp) ...@@ -348,7 +348,7 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp)
return __sev_do_cmd_locked(cmd, NULL, &argp->error); return __sev_do_cmd_locked(cmd, NULL, &argp->error);
} }
static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp) static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_pek_csr input; struct sev_user_data_pek_csr input;
...@@ -356,7 +356,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp) ...@@ -356,7 +356,7 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp)
void *blob = NULL; void *blob = NULL;
int ret; int ret;
if (!capable(CAP_SYS_ADMIN)) if (!writable)
return -EPERM; return -EPERM;
if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
...@@ -539,7 +539,7 @@ static int sev_update_firmware(struct device *dev) ...@@ -539,7 +539,7 @@ static int sev_update_firmware(struct device *dev)
return ret; return ret;
} }
static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp) static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_pek_cert_import input; struct sev_user_data_pek_cert_import input;
...@@ -547,7 +547,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp) ...@@ -547,7 +547,7 @@ static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp)
void *pek_blob, *oca_blob; void *pek_blob, *oca_blob;
int ret; int ret;
if (!capable(CAP_SYS_ADMIN)) if (!writable)
return -EPERM; return -EPERM;
if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) if (copy_from_user(&input, (void __user *)argp->data, sizeof(input)))
...@@ -698,7 +698,7 @@ static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp) ...@@ -698,7 +698,7 @@ static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp)
return ret; return ret;
} }
static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp) static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable)
{ {
struct sev_device *sev = psp_master->sev_data; struct sev_device *sev = psp_master->sev_data;
struct sev_user_data_pdh_cert_export input; struct sev_user_data_pdh_cert_export input;
...@@ -708,7 +708,7 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp) ...@@ -708,7 +708,7 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp)
/* If platform is not in INIT state then transition it to INIT. */ /* If platform is not in INIT state then transition it to INIT. */
if (sev->state != SEV_STATE_INIT) { if (sev->state != SEV_STATE_INIT) {
if (!capable(CAP_SYS_ADMIN)) if (!writable)
return -EPERM; return -EPERM;
ret = __sev_platform_init_locked(&argp->error); ret = __sev_platform_init_locked(&argp->error);
...@@ -801,6 +801,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) ...@@ -801,6 +801,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
struct sev_issue_cmd input; struct sev_issue_cmd input;
int ret = -EFAULT; int ret = -EFAULT;
bool writable = file->f_mode & FMODE_WRITE;
if (!psp_master || !psp_master->sev_data) if (!psp_master || !psp_master->sev_data)
return -ENODEV; return -ENODEV;
...@@ -819,25 +820,25 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) ...@@ -819,25 +820,25 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
switch (input.cmd) { switch (input.cmd) {
case SEV_FACTORY_RESET: case SEV_FACTORY_RESET:
ret = sev_ioctl_do_reset(&input); ret = sev_ioctl_do_reset(&input, writable);
break; break;
case SEV_PLATFORM_STATUS: case SEV_PLATFORM_STATUS:
ret = sev_ioctl_do_platform_status(&input); ret = sev_ioctl_do_platform_status(&input);
break; break;
case SEV_PEK_GEN: case SEV_PEK_GEN:
ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PEK_GEN, &input); ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PEK_GEN, &input, writable);
break; break;
case SEV_PDH_GEN: case SEV_PDH_GEN:
ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input); ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input, writable);
break; break;
case SEV_PEK_CSR: case SEV_PEK_CSR:
ret = sev_ioctl_do_pek_csr(&input); ret = sev_ioctl_do_pek_csr(&input, writable);
break; break;
case SEV_PEK_CERT_IMPORT: case SEV_PEK_CERT_IMPORT:
ret = sev_ioctl_do_pek_import(&input); ret = sev_ioctl_do_pek_import(&input, writable);
break; break;
case SEV_PDH_CERT_EXPORT: case SEV_PDH_CERT_EXPORT:
ret = sev_ioctl_do_pdh_export(&input); ret = sev_ioctl_do_pdh_export(&input, writable);
break; break;
case SEV_GET_ID: case SEV_GET_ID:
pr_warn_once("SEV_GET_ID command is deprecated, use SEV_GET_ID2\n"); pr_warn_once("SEV_GET_ID command is deprecated, use SEV_GET_ID2\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment