aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDongsheng Yang <yangds.fnst@cn.fujitsu.com>2015-08-18 00:38:36 -0400
committerRichard Weinberger <richard@nod.at>2015-11-07 05:33:17 -0500
commitab92a20bce3b4c21927cc1ae514c482f50ad3487 (patch)
tree5979820c9a40bf54a7542a3df9f75c0482aea70b
parent54bcfdf19ec7c2f2788fa76426c91abdc4dab973 (diff)
ubifs: make ubifs_[get|set]xattr atomic
This commit make the ubifs_[get|set]xattr protected by ui_mutex. Originally, there is a possibility that ubifs_getxattr to get a wrong value. P1 P2 ---------- ---------- ubifs_getxattr ubifs_setxattr - kfree() - memcpy() - kmemdup() Then ubifs_getxattr() would get a non-sense data. To solve this problem, this commit make the xattr of ubifs_inode updated in atomic. Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--fs/ubifs/xattr.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 96f3448b6eb4..99364aeed035 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -200,6 +200,7 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
200 int err; 200 int err;
201 struct ubifs_inode *host_ui = ubifs_inode(host); 201 struct ubifs_inode *host_ui = ubifs_inode(host);
202 struct ubifs_inode *ui = ubifs_inode(inode); 202 struct ubifs_inode *ui = ubifs_inode(inode);
203 void *buf = NULL;
203 struct ubifs_budget_req req = { .dirtied_ino = 2, 204 struct ubifs_budget_req req = { .dirtied_ino = 2,
204 .dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) }; 205 .dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
205 206
@@ -208,14 +209,17 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
208 if (err) 209 if (err)
209 return err; 210 return err;
210 211
211 kfree(ui->data); 212 buf = kmemdup(value, size, GFP_NOFS);
212 ui->data = kmemdup(value, size, GFP_NOFS); 213 if (!buf) {
213 if (!ui->data) {
214 err = -ENOMEM; 214 err = -ENOMEM;
215 goto out_free; 215 goto out_free;
216 } 216 }
217 mutex_lock(&ui->ui_mutex);
218 kfree(ui->data);
219 ui->data = buf;
217 inode->i_size = ui->ui_size = size; 220 inode->i_size = ui->ui_size = size;
218 ui->data_len = size; 221 ui->data_len = size;
222 mutex_unlock(&ui->ui_mutex);
219 223
220 mutex_lock(&host_ui->ui_mutex); 224 mutex_lock(&host_ui->ui_mutex);
221 host->i_ctime = ubifs_current_time(host); 225 host->i_ctime = ubifs_current_time(host);
@@ -409,6 +413,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
409 ubifs_assert(inode->i_size == ui->data_len); 413 ubifs_assert(inode->i_size == ui->data_len);
410 ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len); 414 ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len);
411 415
416 mutex_lock(&ui->ui_mutex);
412 if (buf) { 417 if (buf) {
413 /* If @buf is %NULL we are supposed to return the length */ 418 /* If @buf is %NULL we are supposed to return the length */
414 if (ui->data_len > size) { 419 if (ui->data_len > size) {
@@ -423,6 +428,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
423 err = ui->data_len; 428 err = ui->data_len;
424 429
425out_iput: 430out_iput:
431 mutex_unlock(&ui->ui_mutex);
426 iput(inode); 432 iput(inode);
427out_unlock: 433out_unlock:
428 kfree(xent); 434 kfree(xent);