As far as I can tell, the S_ISREG() check is there to prevent executing files where that would be nonsensical, like directories, fifos, or sockets. But the semantics for executing a block device are quite obvious — the block device acts just like a regular file. My use case is having a common VM image that takes a configurable payload to run. The payload will always be a single ELF file. I could share the file with virtio-fs, or I could create a disk image containing a filesystem containing the payload, but both of those add unnecessary layers of indirection when all I need to do is share a single executable blob with the VM. Sharing it as a block device is the most natural thing to do, aside from the (arbitrary, as far as I can tell) restriction on executing block devices. (The only slight complexity is that I need to ensure that my payload size is rounded up to a whole number of sectors, but that's trivial and fast in comparison to e.g. generating a filesystem image.) Signed-off-by: Alyssa Ross <hi@xxxxxxxxx> --- fs/exec.c | 6 ++++-- fs/namei.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 6518e33ea813..e29a9f16da5f 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -148,7 +148,8 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) * and check again at the very end too. */ error = -EACCES; - if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) || + if (WARN_ON_ONCE((!S_ISREG(file_inode(file)->i_mode) && + !S_ISBLK(file_inode(file)->i_mode)) || path_noexec(&file->f_path))) goto exit; @@ -931,7 +932,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags) * and check again at the very end too. */ err = -EACCES; - if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) || + if (WARN_ON_ONCE((!S_ISREG(file_inode(file)->i_mode) && + !S_ISBLK(file_inode(file)->i_mode)) || path_noexec(&file->f_path))) goto exit; diff --git a/fs/namei.c b/fs/namei.c index 567ee547492b..60c89321604a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3254,7 +3254,7 @@ static int may_open(struct mnt_idmap *idmap, const struct path *path, fallthrough; case S_IFIFO: case S_IFSOCK: - if (acc_mode & MAY_EXEC) + if ((inode->i_mode & S_IFMT) != S_IFBLK && (acc_mode & MAY_EXEC)) return -EACCES; flag &= ~O_TRUNC; break; base-commit: 94f6f0550c625fab1f373bb86a6669b45e9748b3 -- 2.42.0