From 895d9db253a0b0b1f8a6e635fb2460d80bf72d5a Mon Sep 17 00:00:00 2001 From: Subodh Nijsure Date: Fri, 31 Oct 2014 13:50:29 -0500 Subject: UBIFS: Add xattr support for symlinks Artem: rename the __ubifs_setxattr() functions to just 'setxattr()'. Signed-off-by: Subodh Nijsure Signed-off-by: Marc Kleine-Budde Signed-off-by: Ben Shelton Acked-by: Terry Wilcox Acked-by: Gratian Crisan Signed-off-by: Artem Bityutskiy --- fs/ubifs/file.c | 4 ++++ fs/ubifs/xattr.c | 17 ++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'fs/ubifs') diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 538519ee37d9..4855abcfe256 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1574,6 +1574,10 @@ const struct inode_operations ubifs_symlink_inode_operations = { .follow_link = ubifs_follow_link, .setattr = ubifs_setattr, .getattr = ubifs_getattr, + .setxattr = ubifs_setxattr, + .getxattr = ubifs_getxattr, + .listxattr = ubifs_listxattr, + .removexattr = ubifs_removexattr, }; const struct file_operations ubifs_file_operations = { diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index 5e0a63b1b0d5..c3254a681a78 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c @@ -293,18 +293,16 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum) return ERR_PTR(-EINVAL); } -int ubifs_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) +static int setxattr(struct inode *host, const char *name, const void *value, + size_t size, int flags) { - struct inode *inode, *host = dentry->d_inode; + struct inode *inode; struct ubifs_info *c = host->i_sb->s_fs_info; struct qstr nm = QSTR_INIT(name, strlen(name)); struct ubifs_dent_node *xent; union ubifs_key key; int err, type; - dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd", name, - host->i_ino, dentry, size); ubifs_assert(mutex_is_locked(&host->i_mutex)); if (size > UBIFS_MAX_INO_DATA) @@ -356,6 +354,15 @@ out_free: return err; } +int ubifs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd", + name, dentry->d_inode->i_ino, dentry, size); + + return setxattr(dentry->d_inode, name, value, size, flags); +} + ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, size_t size) { -- cgit v1.2.3 From d7f0b70d30ffb9bbe6b8a3e1035cf0b79965ef53 Mon Sep 17 00:00:00 2001 From: Subodh Nijsure Date: Fri, 31 Oct 2014 13:50:30 -0500 Subject: UBIFS: Add security.* XATTR support for the UBIFS Artem: rename static functions so that they do not use the "ubifs_" prefix - we only use this prefix for non-static functions. Artem: remove few junk white-space changes in file.c Signed-off-by: Subodh Nijsure Signed-off-by: Marc Kleine-Budde Signed-off-by: Ben Shelton Acked-by: Brad Mouring Acked-by: Terry Wilcox Acked-by: Gratian Crisan Signed-off-by: Artem Bityutskiy --- fs/ubifs/dir.c | 16 ++++++++++++ fs/ubifs/super.c | 1 + fs/ubifs/ubifs.h | 4 +++ fs/ubifs/xattr.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) (limited to 'fs/ubifs') diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index ea41649e4ca5..f7e8f765b36f 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -272,6 +272,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, goto out_budg; } + err = ubifs_init_security(dir, inode, &dentry->d_name); + if (err) + goto out_cancel; + mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; @@ -728,6 +732,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) goto out_budg; } + err = ubifs_init_security(dir, inode, &dentry->d_name); + if (err) + goto out_cancel; + mutex_lock(&dir_ui->ui_mutex); insert_inode_hash(inode); inc_nlink(inode); @@ -808,6 +816,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ui->data = dev; ui->data_len = devlen; + err = ubifs_init_security(dir, inode, &dentry->d_name); + if (err) + goto out_cancel; + mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; @@ -884,6 +896,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ui->data_len = len; inode->i_size = ubifs_inode(inode)->ui_size = len; + err = ubifs_init_security(dir, inode, &dentry->d_name); + if (err) + goto out_cancel; + mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 106bf20629ce..e6420677cebc 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2039,6 +2039,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) if (c->max_inode_sz > MAX_LFS_FILESIZE) sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; sb->s_op = &ubifs_super_operations; + sb->s_xattr = ubifs_xattr_handlers; mutex_lock(&c->umount_mutex); err = mount_ubifs(c); diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index c4fe900c67ab..bc04b9c69891 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "ubifs-media.h" /* Version of this UBIFS implementation */ @@ -1465,6 +1466,7 @@ extern spinlock_t ubifs_infos_lock; extern atomic_long_t ubifs_clean_zn_cnt; extern struct kmem_cache *ubifs_inode_slab; extern const struct super_operations ubifs_super_operations; +extern const struct xattr_handler *ubifs_xattr_handlers[]; extern const struct address_space_operations ubifs_file_address_operations; extern const struct file_operations ubifs_file_operations; extern const struct inode_operations ubifs_file_inode_operations; @@ -1754,6 +1756,8 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, size_t size); ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size); int ubifs_removexattr(struct dentry *dentry, const char *name); +int ubifs_init_security(struct inode *dentry, struct inode *inode, + const struct qstr *qstr); /* super.c */ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum); diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index c3254a681a78..2bdab8b11f3f 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c @@ -575,3 +575,81 @@ out_free: kfree(xent); return err; } + +static size_t security_listxattr(struct dentry *d, char *list, size_t list_size, + const char *name, size_t name_len, int flags) +{ + const int prefix_len = XATTR_SECURITY_PREFIX_LEN; + const size_t total_len = prefix_len + name_len + 1; + + if (list && total_len <= list_size) { + memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); + memcpy(list + prefix_len, name, name_len); + list[prefix_len + name_len] = '\0'; + } + + return total_len; +} + +static int security_getxattr(struct dentry *d, const char *name, void *buffer, + size_t size, int flags) +{ + return ubifs_getxattr(d, name, buffer, size); +} + +static int security_setxattr(struct dentry *d, const char *name, + const void *value, size_t size, int flags, + int handler_flags) +{ + return ubifs_setxattr(d, name, value, size, flags); +} + +static const struct xattr_handler ubifs_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = security_listxattr, + .get = security_getxattr, + .set = security_setxattr, +}; + +const struct xattr_handler *ubifs_xattr_handlers[] = { + &ubifs_xattr_security_handler, + NULL, +}; + +static int init_xattrs(struct inode *inode, const struct xattr *xattr_array, + void *fs_info) +{ + const struct xattr *xattr; + char *name; + int err = 0; + + for (xattr = xattr_array; xattr->name != NULL; xattr++) { + name = kmalloc(XATTR_SECURITY_PREFIX_LEN + + strlen(xattr->name) + 1, GFP_NOFS); + if (!name) { + err = -ENOMEM; + break; + } + strcpy(name, XATTR_SECURITY_PREFIX); + strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name); + err = setxattr(inode, name, xattr->value, xattr->value_len, 0); + kfree(name); + if (err < 0) + break; + } + + return err; +} + +int ubifs_init_security(struct inode *dentry, struct inode *inode, + const struct qstr *qstr) +{ + int err; + + mutex_lock(&inode->i_mutex); + err = security_inode_init_security(inode, dentry, qstr, + &init_xattrs, 0); + mutex_unlock(&inode->i_mutex); + + return err; +} -- cgit v1.2.3 From fee1756d80c24d5a3171cb9f76d612e512439dd2 Mon Sep 17 00:00:00 2001 From: Subodh Nijsure Date: Fri, 31 Oct 2014 13:50:31 -0500 Subject: UBIFS: add ubifs_err() to print error reason This patch adds ubifs_err() output to some error paths to tell the user what's going on. Artem: improve the messages, rename too long variable Signed-off-by: Subodh Nijsure Signed-off-by: Marc Kleine-Budde Signed-off-by: Ben Shelton Acked-by: Brad Mouring Acked-by: Terry Wilcox Acked-by: Gratian Crisan Signed-off-by: Artem Bityutskiy --- fs/ubifs/xattr.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'fs/ubifs') diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index 2bdab8b11f3f..a92be244a6fb 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c @@ -100,24 +100,30 @@ static const struct file_operations empty_fops; static int create_xattr(struct ubifs_info *c, struct inode *host, const struct qstr *nm, const void *value, int size) { - int err; + int err, names_len; struct inode *inode; struct ubifs_inode *ui, *host_ui = ubifs_inode(host); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(size, 8), .dirtied_ino = 1, .dirtied_ino_d = ALIGN(host_ui->data_len, 8) }; - if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) + if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) { + ubifs_err("inode %lu already has too many xattrs (%d), cannot create more", + host->i_ino, host_ui->xattr_cnt); return -ENOSPC; + } /* * Linux limits the maximum size of the extended attribute names list * to %XATTR_LIST_MAX. This means we should not allow creating more * extended attributes if the name list becomes larger. This limitation * is artificial for UBIFS, though. */ - if (host_ui->xattr_names + host_ui->xattr_cnt + - nm->len + 1 > XATTR_LIST_MAX) + names_len = host_ui->xattr_names + host_ui->xattr_cnt + nm->len + 1; + if (names_len > XATTR_LIST_MAX) { + ubifs_err("cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d", + host->i_ino, names_len, XATTR_LIST_MAX); return -ENOSPC; + } err = ubifs_budget_space(c, &req); if (err) @@ -651,5 +657,8 @@ int ubifs_init_security(struct inode *dentry, struct inode *inode, &init_xattrs, 0); mutex_unlock(&inode->i_mutex); + if (err) + ubifs_err("cannot initialize security for inode %lu, error %d", + inode->i_ino, err); return err; } -- cgit v1.2.3 From fb4325a3d9f983160f142b919880ccbe2304bc25 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 25 Nov 2014 16:41:26 +0200 Subject: UBIFS: add a couple of extra asserts ... to catch possible memory corruptions. Reported-by: Dan Carpenter Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/ubifs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 7ed13e1e216a..4cfb3e82c56f 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2032,6 +2032,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr, long long blk_offs; struct ubifs_data_node *dn = node; + ubifs_assert(zbr->len >= UBIFS_DATA_NODE_SZ); + /* * Search the inode node this data node belongs to and insert * it to the RB-tree of inodes. @@ -2060,6 +2062,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr, struct ubifs_dent_node *dent = node; struct fsck_inode *fscki1; + ubifs_assert(zbr->len >= UBIFS_DENT_NODE_SZ); + err = ubifs_validate_entry(c, dent); if (err) goto out_dump; -- cgit v1.2.3 From 88cff0f0fbcf64cb6c2fbad6cf57e2725475d0ee Mon Sep 17 00:00:00 2001 From: hujianyang Date: Tue, 10 Feb 2015 11:28:57 +0800 Subject: UBIFS: return -EINVAL if log head is empty CS node is recognized as a sign in UBIFS log replay mechanism. Log relaying during mount should find the CS node in log head at beginning and then replay the following uncommitted buds. Here is a bug in log replay path: If the log head, which is indicated by @log_lnum in mst_node, is empty, current UBIFS replay nothing and directly mount the partition without any warning. This action will put filesystem in an abnormal state, e.g. space management in LPT area is incorrect to the real space usage in main area. We reproduced this bug by fault injection: turn log head leb into all 0xFF. UBIFS driver mount the polluted partition normally. But errors occur while running fs_stress on this mount: [89068.055183] UBI error: ubi_io_read: error -74 (ECC error) while reading 59 bytes from PEB 711:33088, read 59 bytes [89068.179877] UBIFS error (pid 10517): ubifs_check_node: bad magic 0x101031, expected 0x6101831 [89068.179882] UBIFS error (pid 10517): ubifs_check_node: bad node at LEB 591:28992 [89068.179891] Not a node, first 24 bytes: [89068.179892] 00000000: 31 10 10 00 37 84 64 04 10 04 00 00 00 00 00 00 20 00 00 00 02 01 00 00 1...7.d......... ....... [89068.180282] UBIFS error (pid 10517): ubifs_read_node: expected node type 2 This patch fix the problem by checking *lnum* to guarantee the empty leb is not log head leb and return an error if the log head leb is incorrectly empty. After this, we could catch *log head empty* error in place. Signed-off-by: hujianyang Signed-off-by: Artem Bityutskiy --- fs/ubifs/replay.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'fs/ubifs') diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index 3187925e9879..9b40a1c5e160 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -1028,9 +1028,22 @@ int ubifs_replay_journal(struct ubifs_info *c) do { err = replay_log_leb(c, lnum, 0, c->sbuf); - if (err == 1) - /* We hit the end of the log */ - break; + if (err == 1) { + if (lnum != c->lhead_lnum) + /* We hit the end of the log */ + break; + + /* + * The head of the log must always start with the + * "commit start" node on a properly formatted UBIFS. + * But we found no nodes at all, which means that + * someting went wrong and we cannot proceed mounting + * the file-system. + */ + ubifs_err("no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted", + lnum, 0); + err = -EINVAL; + } if (err) goto out; lnum = ubifs_next_log_lnum(c, lnum); -- cgit v1.2.3