[PATCH] mtd: mtd-utils: Support Capabilities (extended attributes)

Bruno Vernay brunovern.a at gmail.com
Tue Jan 13 02:16:55 PST 2015


On Wed, Dec 10, 2014 at 10:45 AM, Bruno Vernay <brunovern.a at gmail.com> wrote:
>
> [PATCH]  mtd: mtd-utils: Support Capabilities (extended attributes)
>
> Write the files capabilities into the target image.
> Capabilities are a kind of security extended attributes (similar to SELinux)
> The extended attributes are writen in an additional inode.
> Note that we don't use the "capability" functions, but the raw
> Extended Attributes http://www.linuxhowtos.org/manpages/2/getxattr.htm
> Inspired from: http://patchwork.ozlabs.org/patch/321572/
> About Capabilities: http://www.friedhoff.org/posixfilecaps.html
>
> [From: Bruno VERNAY <brunovern.a at gmail.com>]

Patch inlined instead of being joined as attachment.


>From ead64714066a08a9a2f6bdee078a72d8503c4570 Mon Sep 17 00:00:00 2001
From: Bruno Vernay <Bruno.Vernay at Schneider-Electric.com>
Date: Wed, 10 Dec 2014 10:25:48 +0100
Subject: [PATCH] Support Capabilities

---
 Makefile                |   2 +-
 mkfs.ubifs/key.h        |  18 +++++
 mkfs.ubifs/mkfs.ubifs.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++-
 mkfs.ubifs/ubifs.h      |   9 +++
 4 files changed, 211 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 0b57a3f..20a0dde 100644
--- a/Makefile
+++ b/Makefile
@@ -104,7 +104,7 @@ $(call _mkdep,lib/,libmtd.a)
 obj-mkfs.ubifs = crc16.o lpt.o compr.o devtable.o \
  hashtable/hashtable.o hashtable/hashtable_itr.o
 LDFLAGS_mkfs.ubifs = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
-LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid
+LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid -lcap
 $(call mkdep,mkfs.ubifs/,mkfs.ubifs,,ubi-utils/libubi.a)

 #
diff --git a/mkfs.ubifs/key.h b/mkfs.ubifs/key.h
index d3a02d4..8d9112c 100644
--- a/mkfs.ubifs/key.h
+++ b/mkfs.ubifs/key.h
@@ -119,6 +119,24 @@ static inline void dent_key_init(const struct
ubifs_info *c,
 }

 /**
+ * xent_key_init - initialize extended attribute entry key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: host inode number
+ * @nm: extended attribute entry name and length
+ */
+static inline void xent_key_init(const struct ubifs_info *c,
+             union ubifs_key *key, ino_t inum,
+             const struct qstr *nm)
+{
+   uint32_t hash = c->key_hash(nm->name, nm->len);
+
+   ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+   key->u32[0] = inum;
+   key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
+}
+
+/**
  * data_key_init - initialize data key.
  * @c: UBIFS file-system description object
  * @key: key to initialize
diff --git a/mkfs.ubifs/mkfs.ubifs.c b/mkfs.ubifs/mkfs.ubifs.c
index ca17e2b..abde979 100644
--- a/mkfs.ubifs/mkfs.ubifs.c
+++ b/mkfs.ubifs/mkfs.ubifs.c
@@ -25,6 +25,9 @@
 #include "mkfs.ubifs.h"
 #include <crc32.h>
 #include "common.h"
+#include <sys/capability.h>
+#include <sys/types.h>
+#include <sys/xattr.h>

 /* Size (prime number) of hash table for link counting */
 #define HASH_TABLE_SIZE 10099
@@ -1054,6 +1057,163 @@ static int add_inode_with_data(struct stat
*st, ino_t inum, void *data,
 }

 /**
+ * add_inode_with_xattr - write an inode with xattr support.  much like the
+ *    with_data function above but creates 3 nodes: The inode for the file/
+ *    directory with xattr size set, the xent node with the same inum as the
+ *    previous inode and finally the inode with the actual capability data and
+ *    a new unique inum value.
+ * @st: stat information of source inode
+ * @inum: target inode number
+ * @data: inode data (for special inodes e.g. symlink path etc)
+ * @data_len: inode data length
+ * @flags: source inode flags
+ */
+static int add_inode_with_xattr(struct stat *st, ino_t inum, void *data,
+                               unsigned int data_len, int flags)
+{
+        struct ubifs_ino_node *ino = node_buf;
+        struct ubifs_dent_node *xent = node_buf;
+        union ubifs_key key, xkey, nkey;
+        int len, use_flags = 0, ret;
+        char *name;
+        struct qstr nm;
+
+        if (c->default_compr != UBIFS_COMPR_NONE)
+                use_flags |= UBIFS_COMPR_FL;
+        if (flags & FS_COMPR_FL)
+                use_flags |= UBIFS_COMPR_FL;
+        if (flags & FS_SYNC_FL)
+                use_flags |= UBIFS_SYNC_FL;
+        if (flags & FS_IMMUTABLE_FL)
+                use_flags |= UBIFS_IMMUTABLE_FL;
+        if (flags & FS_APPEND_FL)
+                use_flags |= UBIFS_APPEND_FL;
+        if (flags & FS_DIRSYNC_FL && S_ISDIR(st->st_mode))
+                use_flags |= UBIFS_DIRSYNC_FL;
+
+        // file inode
+        memset(ino, 0, UBIFS_INO_NODE_SZ);
+
+        ino_key_init(&key, inum);
+        ino->ch.node_type = UBIFS_INO_NODE;
+        key_write(&key, &ino->key);
+        ino->creat_sqnum = cpu_to_le64(creat_sqnum);
+        ino->size       = cpu_to_le64(st->st_size);
+        ino->nlink      = cpu_to_le32(st->st_nlink);
+        /*
+         * The time fields are updated assuming the default time granularity
+         * of 1 second. To support finer granularities, utime() would
be needed.
+         */
+        ino->atime_sec  = cpu_to_le64(st->st_atime);
+        ino->ctime_sec  = cpu_to_le64(st->st_ctime);
+        ino->mtime_sec  = cpu_to_le64(st->st_mtime);
+        ino->atime_nsec = 0;
+        ino->ctime_nsec = 0;
+        ino->mtime_nsec = 0;
+        ino->uid        = cpu_to_le32(st->st_uid);
+        ino->gid        = cpu_to_le32(st->st_gid);
+        ino->mode       = cpu_to_le32(st->st_mode);
+        ino->flags      = cpu_to_le32(use_flags);
+        ino->data_len   = 0;
+        ino->compr_type = cpu_to_le16(c->default_compr);
+
+        name = strdup(XATTR_NAME_CAPS);
+        if ( name == NULL ) printf("alloc failed\n");
+        nm.name = (void *)name;
+        nm.len = strlen(name);
+
+        ino->xattr_cnt = 1;
+        ino->xattr_size += CALC_DENT_SIZE(strlen(name));
+        ino->xattr_size += CALC_XATTR_BYTES(data_len);
+        ino->xattr_names += strlen(name);
+
+        len = UBIFS_INO_NODE_SZ;
+
+        ret = add_node(&key, name, ino, len) ;
+        if (ret) {
+                printf("host inode add failed\n");
+                return ret;
+        }
+
+        /* do xattr node */
+        memset(xent, 0, UBIFS_XENT_NODE_SZ);
+
+        xent_key_init(c, &xkey, inum, &nm);
+        xent->ch.node_type = UBIFS_XENT_NODE;
+        key_write(&xkey, &xent->key);
+
+        len = UBIFS_XENT_NODE_SZ + strlen(name) + 1;
+
+        xent->ch.len       = len;
+        xent->padding1 = 0;
+        xent->type = UBIFS_ITYPE_DIR;
+        xent->nlen = cpu_to_le16(strlen(name));
+
+        memcpy(xent->name, name, strlen(name) + 1);
+
+        /* unique inum for inode with xattr */
+        inum = ++c->highest_inum;
+        creat_sqnum = ++c->max_sqnum;
+
+        xent->inum = cpu_to_le64(inum);
+
+        ret = add_node(&xkey, name, xent, len);
+        if (ret) {
+                printf("xent inode add failed\n");
+                return ret;
+        }
+
+    /* add inode with xattr data */
+        memset(ino, 0, UBIFS_INO_NODE_SZ);
+
+        ino_key_init(&nkey, inum);
+        ino->ch.node_type = UBIFS_INO_NODE;
+        key_write(&nkey, &ino->key);
+        ino->creat_sqnum = cpu_to_le64(creat_sqnum);
+        ino->size       = cpu_to_le64(data_len);
+        /*
+         * The time fields are updated assuming the default time granularity
+         * of 1 second. To support finer granularities, utime() would
be needed.
+         */
+        ino->atime_sec  = cpu_to_le64(st->st_atime);
+        ino->ctime_sec  = cpu_to_le64(st->st_ctime);
+        ino->mtime_sec  = cpu_to_le64(st->st_mtime);
+        ino->atime_nsec = 0;
+        ino->ctime_nsec = 0;
+        ino->mtime_nsec = 0;
+        ino->uid        = cpu_to_le32(st->st_uid);
+        ino->gid        = cpu_to_le32(st->st_gid);
+        ino->mode       = cpu_to_le32((st->st_mode & (~S_IFDIR)) | (S_IFREG));
+        ino->flags      = cpu_to_le32(UBIFS_XATTR_FL);
+        ino->data_len   = cpu_to_le32(data_len);
+        ino->compr_type = cpu_to_le16(c->default_compr);
+
+        name = strdup(XATTR_NAME_CAPS);
+        if ( name == NULL ) printf("alloc failed\n");
+        nm.name = (void *)name;
+        nm.len = strlen(name);
+
+        ino->xattr_cnt = 1;
+        ino->xattr_size += CALC_DENT_SIZE(strlen(name));
+        ino->xattr_size += CALC_XATTR_BYTES(data_len);
+        ino->xattr_names += strlen(name);
+
+        if (data_len)
+                memcpy(&ino->data, data, data_len);
+
+        len = UBIFS_INO_NODE_SZ + data_len;
+
+        ret = add_node(&nkey, name, ino, len) ;
+        if (ret) {
+                printf("new inode add failed\n");
+                return ret;
+        }
+
+        return ret;
+}
+
+
+/**
  * add_inode - write an inode.
  * @st: stat information of source inode
  * @inum: target inode number
@@ -1234,17 +1394,36 @@ static int add_file(const char *path_name,
struct stat *st, ino_t inum,
     int flags)
 {
  struct ubifs_data_node *dn = node_buf;
- void *buf = block_buf;
+ void *buf = block_buf, *caps;
  loff_t file_size = 0;
- ssize_t ret, bytes_read;
+ ssize_t ret, bytes_read, xattr_len;
  union ubifs_key key;
  int fd, dn_len, err, compr_type, use_compr;
  unsigned int block_no = 0;
  size_t out_len;
+ char *cap_res, *cap_res_ptr, *cap_buf;

  fd = open(path_name, O_RDONLY | O_LARGEFILE);
  if (fd == -1)
  return sys_err_msg("failed to open file '%s'", path_name);
+ xattr_len = fgetxattr(fd, XATTR_NAME_CAPS, NULL, 0);
+ if (xattr_len > 0) {
+ caps = malloc(xattr_len);
+ xattr_len = fgetxattr(fd, XATTR_NAME_CAPS, caps, xattr_len);
+ if (debug_level >= 2) {
+ cap_buf = (char *)caps;
+                cap_res = (char*) malloc(3*xattr_len);
+                cap_res_ptr = cap_res;
+                int i;
+                for (i=0 ; i < xattr_len ; i++) {
+                        cap_res_ptr += sprintf(cap_res_ptr, "%02X:",
cap_buf[i]);
+                };
+                 sprintf(cap_res_ptr-1, "\n");
+                *(cap_res_ptr) = '\0';
+                printf("\n\t%s\tCapability: %s\n", path_name, cap_res);
+ free(cap_res);
+ }
+ };
  do {
  /* Read next block */
  bytes_read = 0;
@@ -1295,6 +1474,8 @@ static int add_file(const char *path_name,
struct stat *st, ino_t inum,
  if (file_size != st->st_size)
  return err_msg("file size changed during writing file '%s'",
        path_name);
+        if (xattr_len > 0)
+                return add_inode_with_xattr(st, inum, caps, xattr_len, flags);
  return add_inode(st, inum, flags);
 }

diff --git a/mkfs.ubifs/ubifs.h b/mkfs.ubifs/ubifs.h
index 434b651..2f080a8 100644
--- a/mkfs.ubifs/ubifs.h
+++ b/mkfs.ubifs/ubifs.h
@@ -42,6 +42,15 @@
  */
 #define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT

+/*
+ * How much a directory entry/extended attribute entry adds to the parent/host
+ * inode.
+ */
+#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8)
+
+/* How much an extended attribute adds to the host inode */
+#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8)
+
 /* The below union makes it easier to deal with keys */
 union ubifs_key
 {
-- 
1.9.1



-- 
Bruno VERNAY



More information about the linux-mtd mailing list