Skip to content

Commit 6cab60a

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 a7fbc7f commit 6cab60a

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
@@ -1262,6 +1262,7 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12621262
unsigned long maxnode)
12631263
{
12641264
unsigned long k;
1265+
unsigned long t;
12651266
unsigned long nlongs;
12661267
unsigned long endmask;
12671268

@@ -1278,13 +1279,19 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12781279
else
12791280
endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1;
12801281

1281-
/* When the user specified more nodes than supported just check
1282-
if the non supported part is all zero. */
1282+
/*
1283+
* When the user specified more nodes than supported just check
1284+
* if the non supported part is all zero.
1285+
*
1286+
* If maxnode have more longs than MAX_NUMNODES, check
1287+
* the bits in that area first. And then go through to
1288+
* check the rest bits which equal or bigger than MAX_NUMNODES.
1289+
* Otherwise, just check bits [MAX_NUMNODES, maxnode).
1290+
*/
12831291
if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) {
12841292
if (nlongs > PAGE_SIZE/sizeof(long))
12851293
return -EINVAL;
12861294
for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) {
1287-
unsigned long t;
12881295
if (get_user(t, nmask + k))
12891296
return -EFAULT;
12901297
if (k == nlongs - 1) {
@@ -1297,6 +1304,16 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
12971304
endmask = ~0UL;
12981305
}
12991306

1307+
if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) {
1308+
unsigned long valid_mask = endmask;
1309+
1310+
valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1);
1311+
if (get_user(t, nmask + nlongs - 1))
1312+
return -EFAULT;
1313+
if (t & valid_mask)
1314+
return -EINVAL;
1315+
}
1316+
13001317
if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long)))
13011318
return -EFAULT;
13021319
nodes_addr(*nodes)[nlongs-1] &= endmask;

0 commit comments

Comments
 (0)