All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] UDF fixes
@ 2017-06-14  9:20 Jan Kara
  2017-06-14  9:20 ` [PATCH 1/5] udf: Fix races with i_size changes during readpage Jan Kara
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Jan Kara @ 2017-06-14  9:20 UTC (permalink / raw)
  To: linux-fsdevel


Hello,

I plan to queue these five UDF fixes into my tree. Review is welcome.

								Honza

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] udf: Fix races with i_size changes during readpage
  2017-06-14  9:20 [PATCH 0/5] UDF fixes Jan Kara
@ 2017-06-14  9:20 ` Jan Kara
  2017-06-14  9:20 ` [PATCH 2/5] udf: Use i_size_read() in udf_adinicb_writepage() Jan Kara
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Jan Kara @ 2017-06-14  9:20 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Jan Kara, stable

__udf_adinicb_readpage() uses i_size several times. When truncate
changes i_size while the function is running, it can observe several
different values and thus e.g. expose uninitialized parts of page to
userspace. Also use i_size_read() in the function since it does not hold
inode_lock. Since i_size is guaranteed to be small, this cannot really
cause any issues even on 32-bit archs but let's be careful.

CC: stable@vger.kernel.org
Fixes: 9c2fc0de1a6e638fe58c354a463f544f42a90a09
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/udf/file.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/udf/file.c b/fs/udf/file.c
index f5eb2d5b3bac..e06d2c15749a 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -43,10 +43,15 @@ static void __udf_adinicb_readpage(struct page *page)
 	struct inode *inode = page->mapping->host;
 	char *kaddr;
 	struct udf_inode_info *iinfo = UDF_I(inode);
+	loff_t isize = i_size_read(inode);
 
+	/*
+	 * We have to be careful here as truncate can change i_size under us.
+	 * So just sample it once and use the same value everywhere.
+	 */
 	kaddr = kmap_atomic(page);
-	memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size);
-	memset(kaddr + inode->i_size, 0, PAGE_SIZE - inode->i_size);
+	memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, isize);
+	memset(kaddr + isize, 0, PAGE_SIZE - isize);
 	flush_dcache_page(page);
 	SetPageUptodate(page);
 	kunmap_atomic(kaddr);
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] udf: Use i_size_read() in udf_adinicb_writepage()
  2017-06-14  9:20 [PATCH 0/5] UDF fixes Jan Kara
  2017-06-14  9:20 ` [PATCH 1/5] udf: Fix races with i_size changes during readpage Jan Kara
@ 2017-06-14  9:20 ` Jan Kara
  2017-06-14  9:20 ` [PATCH 3/5] udf: Fix deadlock between writeback and udf_setsize() Jan Kara
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Jan Kara @ 2017-06-14  9:20 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Jan Kara

We don't hold inode_lock in udf_adinicb_writepage() so use i_size_read()
to get i_size. This cannot cause real problems is i_size is guaranteed
to be small but let's be careful.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/udf/file.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/udf/file.c b/fs/udf/file.c
index e06d2c15749a..356c2bf148a5 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -76,7 +76,8 @@ static int udf_adinicb_writepage(struct page *page,
 	BUG_ON(!PageLocked(page));
 
 	kaddr = kmap_atomic(page);
-	memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size);
+	memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr,
+		i_size_read(inode));
 	SetPageUptodate(page);
 	kunmap_atomic(kaddr);
 	mark_inode_dirty(inode);
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] udf: Fix deadlock between writeback and udf_setsize()
  2017-06-14  9:20 [PATCH 0/5] UDF fixes Jan Kara
  2017-06-14  9:20 ` [PATCH 1/5] udf: Fix races with i_size changes during readpage Jan Kara
  2017-06-14  9:20 ` [PATCH 2/5] udf: Use i_size_read() in udf_adinicb_writepage() Jan Kara
@ 2017-06-14  9:20 ` Jan Kara
  2017-06-14  9:20 ` [PATCH 4/5] udf: Use time64_to_tm for timestamp conversion Jan Kara
  2017-06-14  9:20 ` [PATCH 5/5] udf: Convert udf_disk_stamp_to_time() to use mktime64() Jan Kara
  4 siblings, 0 replies; 6+ messages in thread
From: Jan Kara @ 2017-06-14  9:20 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Jan Kara, stable

udf_setsize() called truncate_setsize() with i_data_sem held. Thus
truncate_pagecache() called from truncate_setsize() could lock a page
under i_data_sem which can deadlock as page lock ranks below
i_data_sem - e. g. writeback can hold page lock and try to acquire
i_data_sem to map a block.

Fix the problem by moving truncate_setsize() calls from under
i_data_sem. It is safe for us to change i_size without holding
i_data_sem as all the places that depend on i_size being stable already
hold inode_lock.

CC: stable@vger.kernel.org
Fixes: 7e49b6f2480cb9a9e7322a91592e56a5c85361f5
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/udf/inode.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 98c510e17203..18fdb9d90812 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1222,8 +1222,8 @@ int udf_setsize(struct inode *inode, loff_t newsize)
 			return err;
 		}
 set_size:
-		truncate_setsize(inode, newsize);
 		up_write(&iinfo->i_data_sem);
+		truncate_setsize(inode, newsize);
 	} else {
 		if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
 			down_write(&iinfo->i_data_sem);
@@ -1240,9 +1240,9 @@ int udf_setsize(struct inode *inode, loff_t newsize)
 					  udf_get_block);
 		if (err)
 			return err;
+		truncate_setsize(inode, newsize);
 		down_write(&iinfo->i_data_sem);
 		udf_clear_extent_cache(inode);
-		truncate_setsize(inode, newsize);
 		udf_truncate_extents(inode);
 		up_write(&iinfo->i_data_sem);
 	}
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] udf: Use time64_to_tm for timestamp conversion
  2017-06-14  9:20 [PATCH 0/5] UDF fixes Jan Kara
                   ` (2 preceding siblings ...)
  2017-06-14  9:20 ` [PATCH 3/5] udf: Fix deadlock between writeback and udf_setsize() Jan Kara
@ 2017-06-14  9:20 ` Jan Kara
  2017-06-14  9:20 ` [PATCH 5/5] udf: Convert udf_disk_stamp_to_time() to use mktime64() Jan Kara
  4 siblings, 0 replies; 6+ messages in thread
From: Jan Kara @ 2017-06-14  9:20 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Jan Kara

UDF on-disk time stamp is stored in a form very similar to struct tm.
Use time64_to_tm() for conversion of seconds since epoch to year, month,
... format and then just copy this as necessary to UDF on-disk
structure to simplify the code.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/udf/udftime.c | 45 +++++++++++----------------------------------
 1 file changed, 11 insertions(+), 34 deletions(-)

diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index 77c331f1a770..b9dadc7e5c35 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -38,6 +38,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/time.h>
 
 #define EPOCH_YEAR 1970
 
@@ -81,9 +82,6 @@ static time_t year_seconds[MAX_YEAR_SECONDS] = {
 /*2038*/ SPY(68, 17, 0)
 };
 
-#define SECS_PER_HOUR	(60 * 60)
-#define SECS_PER_DAY	(SECS_PER_HOUR * 24)
-
 struct timespec *
 udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 {
@@ -119,9 +117,9 @@ udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 struct timestamp *
 udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
 {
-	long int days, rem, y;
-	const unsigned short int *ip;
+	long seconds;
 	int16_t offset;
+	struct tm tm;
 
 	offset = -sys_tz.tz_minuteswest;
 
@@ -130,35 +128,14 @@ udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
 
 	dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF));
 
-	ts.tv_sec += offset * 60;
-	days = ts.tv_sec / SECS_PER_DAY;
-	rem = ts.tv_sec % SECS_PER_DAY;
-	dest->hour = rem / SECS_PER_HOUR;
-	rem %= SECS_PER_HOUR;
-	dest->minute = rem / 60;
-	dest->second = rem % 60;
-	y = 1970;
-
-#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
-#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
-
-	while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
-		long int yg = y + days / 365 - (days % 365 < 0);
-
-		/* Adjust DAYS and Y to match the guessed year.  */
-		days -= ((yg - y) * 365
-			 + LEAPS_THRU_END_OF(yg - 1)
-			 - LEAPS_THRU_END_OF(y - 1));
-		y = yg;
-	}
-	dest->year = cpu_to_le16(y);
-	ip = __mon_yday[__isleap(y)];
-	for (y = 11; days < (long int)ip[y]; --y)
-		continue;
-	days -= ip[y];
-	dest->month = y + 1;
-	dest->day = days + 1;
-
+	seconds = ts.tv_sec + offset * 60;
+	time64_to_tm(seconds, 0, &tm);
+	dest->year = cpu_to_le16(tm.tm_year + 1900);
+	dest->month = tm.tm_mon + 1;
+	dest->day = tm.tm_mday;
+	dest->hour = tm.tm_hour;
+	dest->minute = tm.tm_min;
+	dest->second = tm.tm_sec;
 	dest->centiseconds = ts.tv_nsec / 10000000;
 	dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 -
 					dest->centiseconds * 10000) / 100;
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] udf: Convert udf_disk_stamp_to_time() to use mktime64()
  2017-06-14  9:20 [PATCH 0/5] UDF fixes Jan Kara
                   ` (3 preceding siblings ...)
  2017-06-14  9:20 ` [PATCH 4/5] udf: Use time64_to_tm for timestamp conversion Jan Kara
@ 2017-06-14  9:20 ` Jan Kara
  4 siblings, 0 replies; 6+ messages in thread
From: Jan Kara @ 2017-06-14  9:20 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Jan Kara

Convert udf_disk_stamp_to_time() to use mktime64() to simplify the code.
As a bonus we get working timestamp conversion for dates before epoch
and after 2038 (both of which are allowed by UDF standard).

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/udf/udftime.c | 53 ++---------------------------------------------------
 1 file changed, 2 insertions(+), 51 deletions(-)

diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index b9dadc7e5c35..14626b34d13e 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -40,52 +40,9 @@
 #include <linux/kernel.h>
 #include <linux/time.h>
 
-#define EPOCH_YEAR 1970
-
-#ifndef __isleap
-/* Nonzero if YEAR is a leap year (every 4 years,
-   except every 100th isn't, and every 400th is).  */
-#define	__isleap(year)	\
-  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-#endif
-
-/* How many days come before each month (0-12).  */
-static const unsigned short int __mon_yday[2][13] = {
-	/* Normal years.  */
-	{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
-	/* Leap years.  */
-	{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
-};
-
-#define MAX_YEAR_SECONDS	69
-#define SPD			0x15180	/*3600*24 */
-#define SPY(y, l, s)		(SPD * (365 * y + l) + s)
-
-static time_t year_seconds[MAX_YEAR_SECONDS] = {
-/*1970*/ SPY(0,   0, 0), SPY(1,   0, 0), SPY(2,   0, 0), SPY(3,   1, 0),
-/*1974*/ SPY(4,   1, 0), SPY(5,   1, 0), SPY(6,   1, 0), SPY(7,   2, 0),
-/*1978*/ SPY(8,   2, 0), SPY(9,   2, 0), SPY(10,  2, 0), SPY(11,  3, 0),
-/*1982*/ SPY(12,  3, 0), SPY(13,  3, 0), SPY(14,  3, 0), SPY(15,  4, 0),
-/*1986*/ SPY(16,  4, 0), SPY(17,  4, 0), SPY(18,  4, 0), SPY(19,  5, 0),
-/*1990*/ SPY(20,  5, 0), SPY(21,  5, 0), SPY(22,  5, 0), SPY(23,  6, 0),
-/*1994*/ SPY(24,  6, 0), SPY(25,  6, 0), SPY(26,  6, 0), SPY(27,  7, 0),
-/*1998*/ SPY(28,  7, 0), SPY(29,  7, 0), SPY(30,  7, 0), SPY(31,  8, 0),
-/*2002*/ SPY(32,  8, 0), SPY(33,  8, 0), SPY(34,  8, 0), SPY(35,  9, 0),
-/*2006*/ SPY(36,  9, 0), SPY(37,  9, 0), SPY(38,  9, 0), SPY(39, 10, 0),
-/*2010*/ SPY(40, 10, 0), SPY(41, 10, 0), SPY(42, 10, 0), SPY(43, 11, 0),
-/*2014*/ SPY(44, 11, 0), SPY(45, 11, 0), SPY(46, 11, 0), SPY(47, 12, 0),
-/*2018*/ SPY(48, 12, 0), SPY(49, 12, 0), SPY(50, 12, 0), SPY(51, 13, 0),
-/*2022*/ SPY(52, 13, 0), SPY(53, 13, 0), SPY(54, 13, 0), SPY(55, 14, 0),
-/*2026*/ SPY(56, 14, 0), SPY(57, 14, 0), SPY(58, 14, 0), SPY(59, 15, 0),
-/*2030*/ SPY(60, 15, 0), SPY(61, 15, 0), SPY(62, 15, 0), SPY(63, 16, 0),
-/*2034*/ SPY(64, 16, 0), SPY(65, 16, 0), SPY(66, 16, 0), SPY(67, 17, 0),
-/*2038*/ SPY(68, 17, 0)
-};
-
 struct timespec *
 udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 {
-	int yday;
 	u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
 	u16 year = le16_to_cpu(src.year);
 	uint8_t type = typeAndTimezone >> 12;
@@ -100,15 +57,9 @@ udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 	} else
 		offset = 0;
 
-	if ((year < EPOCH_YEAR) ||
-	    (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
-		return NULL;
-	}
-	dest->tv_sec = year_seconds[year - EPOCH_YEAR];
+	dest->tv_sec = mktime64(year, src.month, src.day, src.hour, src.minute,
+			src.second);
 	dest->tv_sec -= offset * 60;
-
-	yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1);
-	dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
 	dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
 			src.hundredsOfMicroseconds * 100 + src.microseconds);
 	return dest;
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-06-14  9:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-14  9:20 [PATCH 0/5] UDF fixes Jan Kara
2017-06-14  9:20 ` [PATCH 1/5] udf: Fix races with i_size changes during readpage Jan Kara
2017-06-14  9:20 ` [PATCH 2/5] udf: Use i_size_read() in udf_adinicb_writepage() Jan Kara
2017-06-14  9:20 ` [PATCH 3/5] udf: Fix deadlock between writeback and udf_setsize() Jan Kara
2017-06-14  9:20 ` [PATCH 4/5] udf: Use time64_to_tm for timestamp conversion Jan Kara
2017-06-14  9:20 ` [PATCH 5/5] udf: Convert udf_disk_stamp_to_time() to use mktime64() Jan Kara

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.