Signed-off-by: Marko Petrović <petrovicmarko2...@gmail.com>
---
 fs/hostfs/hostfs.h      |  5 ++-
 fs/hostfs/hostfs_kern.c | 23 ++++++++--
 fs/hostfs/hostfs_user.c | 96 +++++++++++++++++++++++++++++++++++++----
 3 files changed, 110 insertions(+), 14 deletions(-)

diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 69cb796f6270..9756303fc089 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -37,6 +37,7 @@
  * is on, and remove the appropriate bits from attr->ia_mode (attr is a
  * "struct iattr *"). -BlaisorBlade
  */
+extern int use_xattr;
 struct hostfs_timespec {
        long long tv_sec;
        long long tv_nsec;
@@ -83,11 +84,11 @@ extern int write_file(int fd, unsigned long long *offset, 
const char *buf,
                      int len);
 extern int lseek_file(int fd, long long offset, int whence);
 extern int fsync_file(int fd, int datasync);
-extern int file_create(char *name, int mode);
+extern int file_create(char *name, int mode, uid_t uid, gid_t gid);
 extern int set_attr(const char *file, struct hostfs_iattr *attrs, int fd);
 extern int make_symlink(const char *from, const char *to);
 extern int unlink_file(const char *file);
-extern int do_mkdir(const char *file, int mode);
+extern int do_mkdir(const char *file, int mode, uid_t uid, gid_t gid);
 extern int hostfs_do_rmdir(const char *file);
 extern int do_mknod(const char *file, int mode, unsigned int major,
                    unsigned int minor);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 28b4f15c19eb..920d211d4e19 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -17,6 +17,7 @@
 #include <linux/writeback.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/uidgid.h>
 #include "hostfs.h"
 #include <init.h>
 #include <kern.h>
@@ -40,6 +41,7 @@ static struct kmem_cache *hostfs_inode_cache;
 /* Changed in hostfs_args before the kernel starts running */
 static char *root_ino = "";
 static int append = 0;
+int use_xattr;
 
 static const struct inode_operations hostfs_iops;
 static const struct inode_operations hostfs_dir_iops;
@@ -50,6 +52,7 @@ static int __init hostfs_args(char *options, int *add)
 {
        char *ptr;
 
+       use_xattr = 0;
        ptr = strchr(options, ',');
        if (ptr != NULL)
                *ptr++ = '\0';
@@ -64,6 +67,8 @@ static int __init hostfs_args(char *options, int *add)
                if (*options != '\0') {
                        if (!strcmp(options, "append"))
                                append = 1;
+                       else if (!strcmp(options, "xattrperm"))
+                               use_xattr = 1;
                        else printf("hostfs_args - unsupported option - %s\n",
                                    options);
                }
@@ -79,8 +84,10 @@ __uml_setup("hostfs=", hostfs_args,
 "    tree on the host.  If this isn't specified, then a user inside UML can\n"
 "    mount anything on the host that's accessible to the user that's running\n"
 "    it.\n"
-"    The only flag currently supported is 'append', which specifies that all\n"
-"    files opened by hostfs will be opened in append mode.\n\n"
+"    The only flags currently supported are 'append', which specifies that\n"
+"    all files opened by hostfs will be opened in append mode and 
'xattrperm'\n"
+"    which specifies that permissions of files will be stored in extended\n"
+"    attributes.\n\n"
 );
 #endif
 
@@ -566,6 +573,8 @@ static int hostfs_create(struct mnt_idmap *idmap, struct 
inode *dir,
        struct inode *inode;
        char *name;
        int error, fd;
+       unsigned int currentuid;
+       unsigned int currentgid;
 
        inode = hostfs_iget(dir->i_sb);
        if (IS_ERR(inode)) {
@@ -578,7 +587,9 @@ static int hostfs_create(struct mnt_idmap *idmap, struct 
inode *dir,
        if (name == NULL)
                goto out_put;
 
-       fd = file_create(name, mode & 0777);
+       currentuid = from_kuid(current->cred->user_ns, current->cred->euid);
+       currentgid = from_kgid(current->cred->user_ns, current->cred->egid);
+       fd = file_create(name, mode & 0777, currentuid, currentgid);
        if (fd < 0)
                error = fd;
        else
@@ -677,10 +688,14 @@ static int hostfs_mkdir(struct mnt_idmap *idmap, struct 
inode *ino,
 {
        char *file;
        int err;
+       unsigned int currentuid;
+       unsigned int currentgid;
 
        if ((file = dentry_name(dentry)) == NULL)
                return -ENOMEM;
-       err = do_mkdir(file, mode);
+       currentuid = from_kuid(current->cred->user_ns, current->cred->euid);
+       currentgid = from_kgid(current->cred->user_ns, current->cred->egid);
+       err = do_mkdir(file, mode, currentuid, currentgid);
        __putname(file);
        return err;
 }
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 5ecc4706172b..fdbd34b9add6 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -15,6 +15,7 @@
 #include <sys/types.h>
 #include <sys/vfs.h>
 #include <sys/syscall.h>
+#include <sys/xattr.h>
 #include "hostfs.h"
 #include <utime.h>
 
@@ -38,6 +39,82 @@ static void stat64_to_hostfs(const struct stat64 *buf, 
struct hostfs_stat *p)
        p->min = os_minor(buf->st_rdev);
 }
 
+static int uml_chown(const char *pathname, unsigned int owner, unsigned int 
group)
+{
+       int status;
+
+       if (use_xattr) {
+               if (owner != -1) {
+                       status = setxattr(pathname, "user.umluid", &owner,
+                                                       sizeof(unsigned int), 
0);
+                       if (status < 0)
+                               return status;
+               }
+               if (group != -1) {
+                       status = setxattr(pathname, "user.umlgid", &owner,
+                                                       sizeof(unsigned int), 
0);
+                       if (status < 0)
+                               return status;
+               }
+               return 0;
+       } else {
+               return chown(pathname, owner, group);
+       }
+}
+
+static int uml_fchown(int fd, unsigned int owner, unsigned int group)
+{
+       int status;
+
+       if (use_xattr) {
+               if (owner != -1) {
+                       status = fsetxattr(fd, "user.umluid", &owner,
+                                               sizeof(unsigned int), 0);
+                       if (status < 0)
+                               return status;
+               }
+               if (group != -1) {
+                       status = fsetxattr(fd, "user.umlgid", &owner,
+                                               sizeof(unsigned int), 0);
+                       if (status < 0)
+                               return status;
+               }
+               return 0;
+       } else {
+               return fchown(fd, owner, group);
+       }
+}
+
+static int uml_chmod(const char *pathname, unsigned int mode)
+{
+       if (use_xattr)
+               return setxattr(pathname, "user.umlmode", &mode,
+                                               sizeof(unsigned int), 0);
+       return chmod(pathname, mode);
+}
+
+static int uml_fchmod(int fd, unsigned int mode)
+{
+       if (use_xattr)
+               return fsetxattr(fd, "user.umlmode", &mode,
+                                               sizeof(unsigned int), 0);
+       return fchmod(fd, mode);
+}
+
+static void read_permissions(const char *path, struct hostfs_stat *p)
+{
+       unsigned int mode, uid, gid;
+
+       if (!use_xattr)
+               return;
+       if (getxattr(path, "user.umlmode", &mode, sizeof(unsigned int)) != -1)
+               p->mode = mode;
+       if (getxattr(path, "user.umluid", &uid, sizeof(unsigned int)) != -1)
+               p->uid = uid;
+       if (getxattr(path, "user.umlgid", &gid, sizeof(unsigned int)) != -1)
+               p->gid = gid;
+}
+
 int stat_file(const char *path, struct hostfs_stat *p, int fd)
 {
        struct stat64 buf;
@@ -49,6 +126,7 @@ int stat_file(const char *path, struct hostfs_stat *p, int 
fd)
                return -errno;
        }
        stat64_to_hostfs(&buf, p);
+       read_permissions(path, p);
        return 0;
 }
 
@@ -181,13 +259,14 @@ void close_dir(void *stream)
        closedir(stream);
 }
 
-int file_create(char *name, int mode)
+int file_create(char *name, int mode, unsigned int uid, unsigned int gid)
 {
        int fd;
 
        fd = open64(name, O_CREAT | O_RDWR, mode);
        if (fd < 0)
                return -errno;
+       uml_chown(name, uid, gid);
        return fd;
 }
 
@@ -199,25 +278,25 @@ int set_attr(const char *file, struct hostfs_iattr 
*attrs, int fd)
 
        if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
                if (fd >= 0) {
-                       if (fchmod(fd, attrs->ia_mode) != 0)
+                       if (uml_fchmod(fd, attrs->ia_mode) != 0)
                                return -errno;
-               } else if (chmod(file, attrs->ia_mode) != 0) {
+               } else if (uml_chmod(file, attrs->ia_mode) != 0) {
                        return -errno;
                }
        }
        if (attrs->ia_valid & HOSTFS_ATTR_UID) {
                if (fd >= 0) {
-                       if (fchown(fd, attrs->ia_uid, -1))
+                       if (uml_fchown(fd, attrs->ia_uid, -1))
                                return -errno;
-               } else if (chown(file, attrs->ia_uid, -1)) {
+               } else if (uml_chown(file, attrs->ia_uid, -1)) {
                        return -errno;
                }
        }
        if (attrs->ia_valid & HOSTFS_ATTR_GID) {
                if (fd >= 0) {
-                       if (fchown(fd, -1, attrs->ia_gid))
+                       if (uml_fchown(fd, -1, attrs->ia_gid))
                                return -errno;
-               } else if (chown(file, -1, attrs->ia_gid)) {
+               } else if (uml_chown(file, -1, attrs->ia_gid)) {
                        return -errno;
                }
        }
@@ -294,13 +373,14 @@ int unlink_file(const char *file)
        return 0;
 }
 
-int do_mkdir(const char *file, int mode)
+int do_mkdir(const char *file, int mode, unsigned int uid, unsigned int gid)
 {
        int err;
 
        err = mkdir(file, mode);
        if (err)
                return -errno;
+       uml_chown(file, uid, gid);
        return 0;
 }
 
-- 
2.39.2


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um

Reply via email to