Skip to content

Commit 656d6e6

Browse files
thejhgregkh
authored andcommitted
userns: move user access out of the mutex
commit 5820f14 upstream. The old code would hold the userns_state_mutex indefinitely if memdup_user_nul stalled due to e.g. a userfault region. Prevent that by moving the memdup_user_nul in front of the mutex_lock(). Note: This changes the error precedence of invalid buf/count/*ppos vs map already written / capabilities missing. Fixes: 22d917d ("userns: Rework the user_namespace adding uid/gid...") Cc: [email protected] Signed-off-by: Jann Horn <[email protected]> Acked-by: Christian Brauner <[email protected]> Acked-by: Serge Hallyn <[email protected]> Signed-off-by: Eric W. Biederman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b692c40 commit 656d6e6

File tree

1 file changed

+10
-14
lines changed

1 file changed

+10
-14
lines changed

kernel/user_namespace.c

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,16 @@ static ssize_t map_write(struct file *file, const char __user *buf,
650650
unsigned idx;
651651
struct uid_gid_extent *extent = NULL;
652652
char *kbuf = NULL, *pos, *next_line;
653-
ssize_t ret = -EINVAL;
653+
ssize_t ret;
654+
655+
/* Only allow < page size writes at the beginning of the file */
656+
if ((*ppos != 0) || (count >= PAGE_SIZE))
657+
return -EINVAL;
658+
659+
/* Slurp in the user data */
660+
kbuf = memdup_user_nul(buf, count);
661+
if (IS_ERR(kbuf))
662+
return PTR_ERR(kbuf);
654663

655664
/*
656665
* The userns_state_mutex serializes all writes to any given map.
@@ -684,19 +693,6 @@ static ssize_t map_write(struct file *file, const char __user *buf,
684693
if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
685694
goto out;
686695

687-
/* Only allow < page size writes at the beginning of the file */
688-
ret = -EINVAL;
689-
if ((*ppos != 0) || (count >= PAGE_SIZE))
690-
goto out;
691-
692-
/* Slurp in the user data */
693-
kbuf = memdup_user_nul(buf, count);
694-
if (IS_ERR(kbuf)) {
695-
ret = PTR_ERR(kbuf);
696-
kbuf = NULL;
697-
goto out;
698-
}
699-
700696
/* Parse the user data */
701697
ret = -EINVAL;
702698
pos = kbuf;

0 commit comments

Comments
 (0)