@@ -2153,14 +2153,29 @@ static int lo_do_open(struct lo_data *lo, struct lo_inode *inode,
static int do_create_nosecctx(fuse_req_t req, struct lo_inode *parent_inode,
const char *name, mode_t mode,
- struct fuse_file_info *fi, int *open_fd)
+ struct fuse_file_info *fi, int *open_fd,
+ bool tmpfile)
{
int err, fd;
struct lo_cred old = {};
struct lo_data *lo = lo_data(req);
int flags;
- flags = fi->flags | O_CREAT | O_EXCL;
+ if (tmpfile) {
+ flags = fi->flags | O_TMPFILE;
+ /*
+ * Don't use O_EXCL as we want to link file later. Also reset O_CREAT
+ * otherwise openat() returns -EINVAL.
+ */
+ flags &= ~(O_CREAT | O_EXCL);
+
+ /* O_TMPFILE needs either O_RDWR or O_WRONLY */
+ if ((flags & O_ACCMODE) == O_RDONLY) {
+ flags |= O_RDWR;
+ }
+ } else {
+ flags = fi->flags | O_CREAT | O_EXCL;
+ }
err = lo_change_cred(req, &old, lo->change_umask);
if (err) {
@@ -2191,7 +2206,7 @@ static int do_create_secctx_fscreate(fuse_req_t req,
return err;
}
- err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd);
+ err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd, false);
close_reset_proc_fscreate(fscreate_fd);
if (!err) {
@@ -2200,6 +2215,44 @@ static int do_create_secctx_fscreate(fuse_req_t req,
return err;
}
+static int do_create_secctx_tmpfile(fuse_req_t req,
+ struct lo_inode *parent_inode,
+ const char *name, mode_t mode,
+ struct fuse_file_info *fi,
+ const char *secctx_name, int *open_fd)
+{
+ int err, fd = -1;
+ struct lo_data *lo = lo_data(req);
+ char procname[64];
+
+ err = do_create_nosecctx(req, parent_inode, ".", mode, fi, &fd, true);
+ if (err) {
+ return err;
+ }
+
+ err = fsetxattr(fd, secctx_name, req->secctx.ctx, req->secctx.ctxlen, 0);
+ if (err) {
+ err = errno;
+ goto out;
+ }
+
+ /* Security context set on file. Link it in place */
+ sprintf(procname, "%d", fd);
+ FCHDIR_NOFAIL(lo->proc_self_fd);
+ err = linkat(AT_FDCWD, procname, parent_inode->fd, name,
+ AT_SYMLINK_FOLLOW);
+ err = err == -1 ? errno : 0;
+ FCHDIR_NOFAIL(lo->root.fd);
+
+out:
+ if (!err) {
+ *open_fd = fd;
+ } else if (fd != -1) {
+ close(fd);
+ }
+ return err;
+}
+
static int do_create_secctx_noatomic(fuse_req_t req,
struct lo_inode *parent_inode,
const char *name, mode_t mode,
@@ -2208,7 +2261,7 @@ static int do_create_secctx_noatomic(fuse_req_t req,
{
int err = 0, fd = -1;
- err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd);
+ err = do_create_nosecctx(req, parent_inode, name, mode, fi, &fd, false);
if (err) {
goto out;
}
@@ -2250,20 +2303,31 @@ static int do_lo_create(fuse_req_t req, struct lo_inode *parent_inode,
if (secctx_enabled) {
/*
* If security.selinux has not been remapped and selinux is enabled,
- * use fscreate to set context before file creation.
- * Otherwise fallback to non-atomic method of file creation
- * and xattr settting.
+ * use fscreate to set context before file creation. If not, use
+ * tmpfile method for regular files. Otherwise fallback to
+ * non-atomic method of file creation and xattr settting.
*/
if (!mapped_name && lo->use_fscreate) {
err = do_create_secctx_fscreate(req, parent_inode, name, mode, fi,
open_fd);
goto out;
+ } else if (S_ISREG(mode)) {
+ err = do_create_secctx_tmpfile(req, parent_inode, name, mode, fi,
+ ctxname, open_fd);
+ /*
+ * If filesystem does not support O_TMPFILE, fallback to non-atomic
+ * method.
+ */
+ if (!err || err != EOPNOTSUPP) {
+ goto out;
+ }
}
err = do_create_secctx_noatomic(req, parent_inode, name, mode, fi,
ctxname, open_fd);
} else {
- err = do_create_nosecctx(req, parent_inode, name, mode, fi, open_fd);
+ err = do_create_nosecctx(req, parent_inode, name, mode, fi, open_fd,
+ false);
}
out: