diff options
author | Jacky Li <jackyli@google.com> | 2022-04-14 19:23:25 +0300 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2022-04-29 08:44:57 +0300 |
commit | 05def5cacfa0bd5ba380116046747da07ff5bd78 (patch) | |
tree | c2cdb42364cf79bedd7184a39051786c96bbf914 /drivers/crypto/ccp/sev-dev.c | |
parent | c6d3ffae0d3229e06097f2790f459c96fca5e367 (diff) | |
download | linux-05def5cacfa0bd5ba380116046747da07ff5bd78.tar.xz |
crypto: ccp - Fix the INIT_EX data file open failure
There are 2 common cases when INIT_EX data file might not be
opened successfully and fail the sev initialization:
1. In user namespaces, normal user tasks (e.g. VMM) can change their
current->fs->root to point to arbitrary directories. While
init_ex_path is provided as a module param related to root file
system. Solution: use the root directory of init_task to avoid
accessing the wrong file.
2. Normal user tasks (e.g. VMM) don't have the privilege to access
the INIT_EX data file. Solution: open the file as root and
restore permissions immediately.
Fixes: 3d725965f836 ("crypto: ccp - Add SEV_INIT_EX support")
Signed-off-by: Jacky Li <jackyli@google.com>
Reviewed-by: Peter Gonda <pgonda@google.com>
Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/ccp/sev-dev.c')
-rw-r--r-- | drivers/crypto/ccp/sev-dev.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index fd928199bf1e..799b476fc3e8 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -23,6 +23,7 @@ #include <linux/gfp.h> #include <linux/cpufeature.h> #include <linux/fs.h> +#include <linux/fs_struct.h> #include <asm/smp.h> @@ -170,6 +171,31 @@ static void *sev_fw_alloc(unsigned long len) return page_address(page); } +static struct file *open_file_as_root(const char *filename, int flags, umode_t mode) +{ + struct file *fp; + struct path root; + struct cred *cred; + const struct cred *old_cred; + + task_lock(&init_task); + get_fs_root(init_task.fs, &root); + task_unlock(&init_task); + + cred = prepare_creds(); + if (!cred) + return ERR_PTR(-ENOMEM); + cred->fsuid = GLOBAL_ROOT_UID; + old_cred = override_creds(cred); + + fp = file_open_root(&root, filename, flags, mode); + path_put(&root); + + revert_creds(old_cred); + + return fp; +} + static int sev_read_init_ex_file(void) { struct sev_device *sev = psp_master->sev_data; @@ -181,7 +207,7 @@ static int sev_read_init_ex_file(void) if (!sev_init_ex_buffer) return -EOPNOTSUPP; - fp = filp_open(init_ex_path, O_RDONLY, 0); + fp = open_file_as_root(init_ex_path, O_RDONLY, 0); if (IS_ERR(fp)) { int ret = PTR_ERR(fp); @@ -217,7 +243,7 @@ static void sev_write_init_ex_file(void) if (!sev_init_ex_buffer) return; - fp = filp_open(init_ex_path, O_CREAT | O_WRONLY, 0600); + fp = open_file_as_root(init_ex_path, O_CREAT | O_WRONLY, 0600); if (IS_ERR(fp)) { dev_err(sev->dev, "SEV: could not open file for write, error %ld\n", |