Skip to content

Commit e6e3a48

Browse files
Yisheng Xiegregkh
authored andcommitted
mm/mempolicy: fix the check of nodemask from user
[ Upstream commit 56521e7 ] As Xiaojun reported the ltp of migrate_pages01 will fail on arm64 system which has 4 nodes[0...3], all have memory and CONFIG_NODES_SHIFT=2: migrate_pages01 0 TINFO : test_invalid_nodes migrate_pages01 14 TFAIL : migrate_pages_common.c:45: unexpected failure - returned value = 0, expected: -1 migrate_pages01 15 TFAIL : migrate_pages_common.c:55: call succeeded unexpectedly In this case the test_invalid_nodes of migrate_pages01 will call: SYSC_migrate_pages as: migrate_pages(0, , {0x0000000000000001}, 64, , {0x0000000000000010}, 64) = 0 The new nodes specifies one or more node IDs that are greater than the maximum supported node ID, however, the errno is not set to EINVAL as expected. As man pages of set_mempolicy[1], mbind[2], and migrate_pages[3] mentioned, when nodemask specifies one or more node IDs that are greater than the maximum supported node ID, the errno should set to EINVAL. However, get_nodes only check whether the part of bits [BITS_PER_LONG*BITS_TO_LONGS(MAX_NUMNODES), maxnode) is zero or not, and remain [MAX_NUMNODES, BITS_PER_LONG*BITS_TO_LONGS(MAX_NUMNODES) unchecked. This patch is to check the bits of [MAX_NUMNODES, maxnode) in get_nodes to let migrate_pages set the errno to EINVAL when nodemask specifies one or more node IDs that are greater than the maximum supported node ID, which follows the manpage's guide. [1] http://man7.org/linux/man-pages/man2/set_mempolicy.2.html [2] http://man7.org/linux/man-pages/man2/mbind.2.html [3] http://man7.org/linux/man-pages/man2/migrate_pages.2.html Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Yisheng Xie <[email protected]> Reported-by: Tan Xiaojun <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Chris Salls <[email protected]> Cc: Christopher Lameter <[email protected]> Cc: David Rientjes <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Naoya Horiguchi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d278dc2 commit e6e3a48

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

mm/mempolicy.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,7 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12321232
unsigned long maxnode)
12331233
{
12341234
unsigned long k;
1235+
unsigned long t;
12351236
unsigned long nlongs;
12361237
unsigned long endmask;
12371238

@@ -1248,13 +1249,19 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12481249
else
12491250
endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1;
12501251

1251-
/* When the user specified more nodes than supported just check
1252-
if the non supported part is all zero. */
1252+
/*
1253+
* When the user specified more nodes than supported just check
1254+
* if the non supported part is all zero.
1255+
*
1256+
* If maxnode have more longs than MAX_NUMNODES, check
1257+
* the bits in that area first. And then go through to
1258+
* check the rest bits which equal or bigger than MAX_NUMNODES.
1259+
* Otherwise, just check bits [MAX_NUMNODES, maxnode).
1260+
*/
12531261
if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) {
12541262
if (nlongs > PAGE_SIZE/sizeof(long))
12551263
return -EINVAL;
12561264
for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) {
1257-
unsigned long t;
12581265
if (get_user(t, nmask + k))
12591266
return -EFAULT;
12601267
if (k == nlongs - 1) {
@@ -1267,6 +1274,16 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12671274
endmask = ~0UL;
12681275
}
12691276

1277+
if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) {
1278+
unsigned long valid_mask = endmask;
1279+
1280+
valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1);
1281+
if (get_user(t, nmask + nlongs - 1))
1282+
return -EFAULT;
1283+
if (t & valid_mask)
1284+
return -EINVAL;
1285+
}
1286+
12701287
if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long)))
12711288
return -EFAULT;
12721289
nodes_addr(*nodes)[nlongs-1] &= endmask;

0 commit comments

Comments
 (0)