[Devel] [PATCH RH7] overlayfs: avoid permission check for priveleged processes
Overlayfs temporary override credentials in copy_up function to ones which was used to create mount. Unfortunately vfs_setxattr requires CAP_SYS_ADMIN capability in current user namespace. This leads to strange situations. For example, if overlayfs mount was made inside ve it is impossible to use copy_up from init_user_ns even with CAP_SYS_ADMIN. This is because overriden credentials are not sufficient in init_user_ns to set xattr to file. This is also required for criu since copy_up can be triggered on dump stage: reading inotify fhandle from /proc may start copy_up. Add an option to avoid vfs_setxattr CAP_SYS_ADMIN check if current credentials have CAP_SYS_ADMIN in namespace that is recorded in overlayfs mount superblock. https://jira.sw.ru/browse/PSBM-108122 Signed-off-by: Andrey Zhadchenko --- fs/overlayfs/copy_up.c | 25 +++-- fs/overlayfs/overlayfs.h | 39 ++- fs/overlayfs/util.c | 32 fs/xattr.c | 2 +- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 1564a35..d6b285f 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "overlayfs.h" #define OVL_COPY_UP_CHUNK_SIZE (1 << 20) @@ -321,8 +322,8 @@ out: return fh; } -int ovl_set_origin(struct dentry *dentry, struct dentry *lower, - struct dentry *upper) +int ovl_set_origin_ext(struct dentry *dentry, struct dentry *lower, + struct dentry *upper, int propagate_cap) { const struct ovl_fh *fh = NULL; int err; @@ -341,8 +342,8 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower, /* * Do not fail when upper doesn't support xattrs. */ - err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh, -fh ? fh->len : 0, 0); + err = ovl_check_setxattr_ext(dentry, upper, OVL_XATTR_ORIGIN, fh, +fh ? fh->len : 0, 0, propagate_cap); kfree(fh); return err; @@ -433,6 +434,7 @@ struct ovl_copy_up_ctx { struct dentry *destdir; struct qstr destname; struct dentry *workdir; + int propagate_cap; bool tmpfile; bool origin; bool indexed; @@ -711,7 +713,7 @@ out: } static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, - int flags) + int flags, int propagate_cap) { int err; struct path parentpath; @@ -719,6 +721,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, .parent = parent, .dentry = dentry, .workdir = ovl_workdir(dentry), + .propagate_cap = propagate_cap, }; if (WARN_ON(!ctx.workdir)) @@ -768,9 +771,19 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, return err; } +static int ovl_can_propagate_cap(struct dentry *dentry) +{ + struct super_block *sb = dentry->d_sb; + struct ovl_fs *ofs = sb->s_fs_info; + struct user_namespace *ovl_ns = ofs->creator_cred->user_ns; + + return ns_capable(ovl_ns, CAP_SYS_ADMIN); +} + int ovl_copy_up_flags(struct dentry *dentry, int flags) { int err = 0; + int propagate_cap = ovl_can_propagate_cap(dentry); const struct cred *old_cred = ovl_override_creds(dentry->d_sb); bool disconnected = (dentry->d_flags & DCACHE_DISCONNECTED); @@ -815,7 +828,7 @@ int ovl_copy_up_flags(struct dentry *dentry, int flags) next = parent; } - err = ovl_copy_up_one(parent, next, flags); + err = ovl_copy_up_one(parent, next, flags, propagate_cap); dput(parent); dput(next); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 7052938..6917acd 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -149,15 +149,6 @@ static inline int ovl_do_symlink(struct inode *dir, struct dentry *dentry, return err; } -static inline int ovl_do_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - int err = vfs_setxattr(dentry, name, value, size, flags); - pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, 0x%x) = %i\n", -dentry, name, min((int)size, 48), value, size, flags, err); - return err; -} - static inline int ovl_do_removexattr(struct dentry *dentry, const char *name) { int err = vfs_removexattr(dentry, name); @@ -245,9 +236,12 @@ int ovl_copy_up_start(struct dentry *dentry); void ovl_copy_up_end(struct dentry *dentry); bool ovl_check_origin_xattr(struct dentry *dentry); bool ovl_check_dir_xattr(struct dentry *
[Devel] [PATCH RH8 3/3] vt: selection, push sel_lock up
From: Jiri Slaby sel_lock cannot nest in the console lock. Thanks to syzkaller, the kernel states firmly: > WARNING: possible circular locking dependency detected > 5.6.0-rc3-syzkaller #0 Not tainted > -- > syz-executor.4/20336 is trying to acquire lock: > 8880a2e952a0 (&tty->termios_rwsem){}, at: tty_unthrottle+0x22/0x100 > drivers/tty/tty_ioctl.c:136 > > but task is already holding lock: > 89462e70 (sel_lock){+.+.}, at: paste_selection+0x118/0x470 > drivers/tty/vt/selection.c:374 > > which lock already depends on the new lock. > > the existing dependency chain (in reverse order) is: > > -> #2 (sel_lock){+.+.}: >mutex_lock_nested+0x1b/0x30 kernel/locking/mutex.c:1118 >set_selection_kernel+0x3b8/0x18a0 drivers/tty/vt/selection.c:217 >set_selection_user+0x63/0x80 drivers/tty/vt/selection.c:181 >tioclinux+0x103/0x530 drivers/tty/vt/vt.c:3050 >vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364 This is ioctl(TIOCL_SETSEL). Locks held on the path: console_lock -> sel_lock > -> #1 (console_lock){+.+.}: >console_lock+0x46/0x70 kernel/printk/printk.c:2289 >con_flush_chars+0x50/0x650 drivers/tty/vt/vt.c:3223 >n_tty_write+0xeae/0x1200 drivers/tty/n_tty.c:2350 >do_tty_write drivers/tty/tty_io.c:962 [inline] >tty_write+0x5a1/0x950 drivers/tty/tty_io.c:1046 This is write(). Locks held on the path: termios_rwsem -> console_lock > -> #0 (&tty->termios_rwsem){}: >down_write+0x57/0x140 kernel/locking/rwsem.c:1534 >tty_unthrottle+0x22/0x100 drivers/tty/tty_ioctl.c:136 >mkiss_receive_buf+0x12aa/0x1340 drivers/net/hamradio/mkiss.c:902 >tty_ldisc_receive_buf+0x12f/0x170 drivers/tty/tty_buffer.c:465 >paste_selection+0x346/0x470 drivers/tty/vt/selection.c:389 >tioclinux+0x121/0x530 drivers/tty/vt/vt.c:3055 >vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364 This is ioctl(TIOCL_PASTESEL). Locks held on the path: sel_lock -> termios_rwsem > other info that might help us debug this: > > Chain exists of: > &tty->termios_rwsem --> console_lock --> sel_lock Clearly. From the above, we have: console_lock -> sel_lock sel_lock -> termios_rwsem termios_rwsem -> console_lock Fix this by reversing the console_lock -> sel_lock dependency in ioctl(TIOCL_SETSEL). First, lock sel_lock, then console_lock. Signed-off-by: Jiri Slaby Reported-by: syzbot+26183d9746e62da32...@syzkaller.appspotmail.com Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") Cc: stable Link: https://lore.kernel.org/r/20200228115406.5735-2-jsl...@suse.cz Signed-off-by: Greg Kroah-Hartman https://jira.sw.ru/browse/PSBM-120640 This is a backport of mainline commit e8c75a30a23c6ba63f4ef6895cbf41fd42f21aa2: the affected code is in set_selection() rather than set_selection_kernel(). Signed-off-by: Evgenii Shatokhin --- drivers/tty/vt/selection.c | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 2f378a7cd1fe..c50a05b57470 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -163,7 +163,7 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ char *bp, *obp; int i, ps, pe, multiplier; u16 c; - int mode, ret = 0; + int mode; poke_blanked_console(); if (copy_from_user(&v, sel, sizeof(*sel))) @@ -190,7 +190,6 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ if (ps > pe)/* make sel_start <= sel_end */ swap(ps, pe); - mutex_lock(&sel_lock); if (sel_cons != vc_cons[fg_console].d) { clear_selection(); sel_cons = vc_cons[fg_console].d; @@ -236,10 +235,9 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ break; case TIOCL_SELPOINTER: highlight_pointer(pe); - goto unlock; + return 0; default: - ret = -EINVAL; - goto unlock; + return -EINVAL; } /* remove the pointer */ @@ -261,7 +259,7 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ else if (new_sel_start == sel_start) { if (new_sel_end == sel_end) /* no action required */ - goto unlock; + return 0; else if (new_sel_end > sel_end) /* extend to right */ highlight(sel_end + 2, new_sel_end); else/* contract from right */ @@ -289,8 +287,7 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ if (!bp) {
[Devel] [PATCH RH8 2/3] vt: selection, push console lock down
From: Jiri Slaby We need to nest the console lock in sel_lock, so we have to push it down a bit. Fortunately, the callers of set_selection_* just lock the console lock around the function call. So moving it down is easy. In the next patch, we switch the order. Signed-off-by: Jiri Slaby Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") Cc: stable Link: https://lore.kernel.org/r/20200228115406.5735-1-jsl...@suse.cz Signed-off-by: Greg Kroah-Hartman https://jira.sw.ru/browse/PSBM-120640 This is a backport of mainline commit 4b70dd57a15d2f4685ac6e38056bad93e81e982f: * speakup-related hunk was dropped because that driver does not use set_selection(): it is not exported in this kernel version; * the affected code is in set_selection() rather than set_selection_kernel(). Signed-off-by: Evgenii Shatokhin --- drivers/tty/vt/selection.c | 13 - drivers/tty/vt/vt.c| 2 -- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 2a68d6fdb7b1..2f378a7cd1fe 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -155,7 +155,7 @@ static int store_utf8(u16 c, char *p) * The entire selection process is managed under the console_lock. It's * a lot under the lock but its hardly a performance path */ -int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) +static int __set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; int new_sel_start, new_sel_end, spc; @@ -320,6 +320,17 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t return ret; } +int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) +{ + int ret; + + console_lock(); + ret = __set_selection(sel, tty); + console_unlock(); + + return ret; +} + /* Insert the contents of the selection buffer into the * queue of the tty associated with the current console. * Invoked by ioctl(). diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 29cf1cd7aff0..440a2d085729 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2694,9 +2694,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) switch (type) { case TIOCL_SETSEL: - console_lock(); ret = set_selection((struct tiocl_selection __user *)(p+1), tty); - console_unlock(); break; case TIOCL_PASTESEL: ret = paste_selection(tty); -- 2.27.0 ___ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel
[Devel] [PATCH RH8 1/3] vt: selection, close sel_buffer race
From: Jiri Slaby syzkaller reported this UAF: BUG: KASAN: use-after-free in n_tty_receive_buf_common+0x2481/0x2940 drivers/tty/n_tty.c:1741 Read of size 1 at addr 8880089e40e9 by task syz-executor.1/13184 CPU: 0 PID: 13184 Comm: syz-executor.1 Not tainted 5.4.7 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 Call Trace: ... kasan_report+0xe/0x20 mm/kasan/common.c:634 n_tty_receive_buf_common+0x2481/0x2940 drivers/tty/n_tty.c:1741 tty_ldisc_receive_buf+0xac/0x190 drivers/tty/tty_buffer.c:461 paste_selection+0x297/0x400 drivers/tty/vt/selection.c:372 tioclinux+0x20d/0x4e0 drivers/tty/vt/vt.c:3044 vt_ioctl+0x1bcf/0x28d0 drivers/tty/vt/vt_ioctl.c:364 tty_ioctl+0x525/0x15a0 drivers/tty/tty_io.c:2657 vfs_ioctl fs/ioctl.c:47 [inline] It is due to a race between parallel paste_selection (TIOCL_PASTESEL) and set_selection_user (TIOCL_SETSEL) invocations. One uses sel_buffer, while the other frees it and reallocates a new one for another selection. Add a mutex to close this race. The mutex takes care properly of sel_buffer and sel_buffer_lth only. The other selection global variables (like sel_start, sel_end, and sel_cons) are protected only in set_selection_user. The other functions need quite some more work to close the races of the variables there. This is going to happen later. This likely fixes (I am unsure as there is no reproducer provided) bug 206361 too. It was marked as CVE-2020-8648. Signed-off-by: Jiri Slaby Reported-by: syzbot+59997e8d5cbdc486e...@syzkaller.appspotmail.com References: https://bugzilla.kernel.org/show_bug.cgi?id=206361 Cc: stable Link: https://lore.kernel.org/r/20200210081131.23572-2-jsl...@suse.cz Signed-off-by: Greg Kroah-Hartman https://jira.sw.ru/browse/PSBM-120640 This is a backport of mainline commit 07e6124a1a46b4b5a9b3cacc0c306b50da87abf5: the affected code is in set_selection() rather than set_selection_kernel(). Signed-off-by: Evgenii Shatokhin --- drivers/tty/vt/selection.c | 23 +-- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 90ea1cc52b7a..2a68d6fdb7b1 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,7 @@ static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; static char *sel_buffer; +static DEFINE_MUTEX(sel_lock); /* clear_selection, highlight and highlight_pointer can be called from interrupt (via scrollback/front) */ @@ -161,7 +163,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t char *bp, *obp; int i, ps, pe, multiplier; u16 c; - int mode; + int mode, ret = 0; poke_blanked_console(); if (copy_from_user(&v, sel, sizeof(*sel))) @@ -188,6 +190,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t if (ps > pe)/* make sel_start <= sel_end */ swap(ps, pe); + mutex_lock(&sel_lock); if (sel_cons != vc_cons[fg_console].d) { clear_selection(); sel_cons = vc_cons[fg_console].d; @@ -233,9 +236,10 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t break; case TIOCL_SELPOINTER: highlight_pointer(pe); - return 0; + goto unlock; default: - return -EINVAL; + ret = -EINVAL; + goto unlock; } /* remove the pointer */ @@ -257,7 +261,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t else if (new_sel_start == sel_start) { if (new_sel_end == sel_end) /* no action required */ - return 0; + goto unlock; else if (new_sel_end > sel_end) /* extend to right */ highlight(sel_end + 2, new_sel_end); else/* contract from right */ @@ -285,7 +289,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); - return -ENOMEM; + ret = -ENOMEM; + goto unlock; } kfree(sel_buffer); sel_buffer = bp; @@ -310,7 +315,9 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t } } sel_buffer_lth = bp - sel_buffer; - return 0; +unlock: + mutex_unlock(&sel_lock); + return ret; } /* Insert the contents of the selection buffer into the @@ -338,1
[Devel] [PATCH RH8 0/3] Fixes for CVE-2020-8648
The following mainline commits were backported to fix CVE-2020-8648: * 07e6124a1a46 "vt: selection, close sel_buffer race" * 4b70dd57a15d "vt: selection, push console lock down" * e8c75a30a23c "vt: selection, push sel_lock up" The first one is the fix itself. The other two are needed to prevent a potential deadlock introduced by that fix. https://jira.sw.ru/browse/PSBM-120640 Signed-off-by: Evgenii Shatokhin ___ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel
[Devel] [PATCH RH7 2/2] vt: selection, push sel_lock up
From: Jiri Slaby sel_lock cannot nest in the console lock. Thanks to syzkaller, the kernel states firmly: > WARNING: possible circular locking dependency detected > 5.6.0-rc3-syzkaller #0 Not tainted > -- > syz-executor.4/20336 is trying to acquire lock: > 8880a2e952a0 (&tty->termios_rwsem){}, at: tty_unthrottle+0x22/0x100 > drivers/tty/tty_ioctl.c:136 > > but task is already holding lock: > 89462e70 (sel_lock){+.+.}, at: paste_selection+0x118/0x470 > drivers/tty/vt/selection.c:374 > > which lock already depends on the new lock. > > the existing dependency chain (in reverse order) is: > > -> #2 (sel_lock){+.+.}: >mutex_lock_nested+0x1b/0x30 kernel/locking/mutex.c:1118 >set_selection_kernel+0x3b8/0x18a0 drivers/tty/vt/selection.c:217 >set_selection_user+0x63/0x80 drivers/tty/vt/selection.c:181 >tioclinux+0x103/0x530 drivers/tty/vt/vt.c:3050 >vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364 This is ioctl(TIOCL_SETSEL). Locks held on the path: console_lock -> sel_lock > -> #1 (console_lock){+.+.}: >console_lock+0x46/0x70 kernel/printk/printk.c:2289 >con_flush_chars+0x50/0x650 drivers/tty/vt/vt.c:3223 >n_tty_write+0xeae/0x1200 drivers/tty/n_tty.c:2350 >do_tty_write drivers/tty/tty_io.c:962 [inline] >tty_write+0x5a1/0x950 drivers/tty/tty_io.c:1046 This is write(). Locks held on the path: termios_rwsem -> console_lock > -> #0 (&tty->termios_rwsem){}: >down_write+0x57/0x140 kernel/locking/rwsem.c:1534 >tty_unthrottle+0x22/0x100 drivers/tty/tty_ioctl.c:136 >mkiss_receive_buf+0x12aa/0x1340 drivers/net/hamradio/mkiss.c:902 >tty_ldisc_receive_buf+0x12f/0x170 drivers/tty/tty_buffer.c:465 >paste_selection+0x346/0x470 drivers/tty/vt/selection.c:389 >tioclinux+0x121/0x530 drivers/tty/vt/vt.c:3055 >vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364 This is ioctl(TIOCL_PASTESEL). Locks held on the path: sel_lock -> termios_rwsem > other info that might help us debug this: > > Chain exists of: > &tty->termios_rwsem --> console_lock --> sel_lock Clearly. From the above, we have: console_lock -> sel_lock sel_lock -> termios_rwsem termios_rwsem -> console_lock Fix this by reversing the console_lock -> sel_lock dependency in ioctl(TIOCL_SETSEL). First, lock sel_lock, then console_lock. Signed-off-by: Jiri Slaby Reported-by: syzbot+26183d9746e62da32...@syzkaller.appspotmail.com Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") Cc: stable Link: https://lore.kernel.org/r/20200228115406.5735-2-jsl...@suse.cz Signed-off-by: Greg Kroah-Hartman https://jira.sw.ru/browse/PSBM-121234 This is a backport of mainline commit e8c75a30a23c6ba63f4ef6895cbf41fd42f21aa2: the affected code is in set_selection() rather than set_selection_kernel(). Signed-off-by: Evgenii Shatokhin --- drivers/tty/vt/selection.c | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 1c31746f9f5e..1a2146cfdd98 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -164,7 +164,7 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ char *bp, *obp; int i, ps, pe, multiplier; u16 c; - int mode, ret = 0; + int mode; poke_blanked_console(); @@ -204,7 +204,6 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ pe = tmp; } - mutex_lock(&sel_lock); if (sel_cons != vc_cons[fg_console].d) { clear_selection(); sel_cons = vc_cons[fg_console].d; @@ -250,10 +249,9 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ break; case TIOCL_SELPOINTER: highlight_pointer(pe); - goto unlock; + return 0; default: - ret = -EINVAL; - goto unlock; + return -EINVAL; } /* remove the pointer */ @@ -275,7 +273,7 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ else if (new_sel_start == sel_start) { if (new_sel_end == sel_end) /* no action required */ - goto unlock; + return 0; else if (new_sel_end > sel_end) /* extend to right */ highlight(sel_end + 2, new_sel_end); else/* contract from right */ @@ -302,8 +300,7 @@ static int __set_selection(const struct tiocl_selection __user *sel, struct tty_ if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); -
[Devel] [PATCH RH7 0/2] Follow-up fixes for CVE-2020-8648
It looks like the following two fixes from the mainline kernel are required to prevent a potential deadlock. commit 4b70dd57a15d2f4685ac6e38056bad93e81e982f Author: Jiri Slaby Date: Fri Feb 28 12:54:05 2020 +0100 vt: selection, push console lock down commit e8c75a30a23c6ba63f4ef6895cbf41fd42f21aa2 Author: Jiri Slaby Date: Fri Feb 28 12:54:06 2020 +0100 vt: selection, push sel_lock up The problem was introduced by the fix for CVE-2020-8648: commit 3bd8c9162241 "ms/vt: selection, close sel_buffer race" in vzkernel. I was unable to reproduce the problem in VZ7 though but the code does look problematic without these fixes. https://jira.sw.ru/browse/PSBM-121234 Signed-off-by: Evgenii Shatokhin ___ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel
[Devel] [PATCH RH7 1/2] vt: selection, push console lock down
From: Jiri Slaby We need to nest the console lock in sel_lock, so we have to push it down a bit. Fortunately, the callers of set_selection_* just lock the console lock around the function call. So moving it down is easy. In the next patch, we switch the order. Signed-off-by: Jiri Slaby Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") Cc: stable Link: https://lore.kernel.org/r/20200228115406.5735-1-jsl...@suse.cz Signed-off-by: Greg Kroah-Hartman https://jira.sw.ru/browse/PSBM-121234 This is a backport of mainline commit 4b70dd57a15d2f4685ac6e38056bad93e81e982f: * speakup-related hunk was dropped because that driver does not use set_selection(): it is not exported in this kernel version; * the affected code is in set_selection() rather than set_selection_kernel(). Signed-off-by: Evgenii Shatokhin --- drivers/tty/vt/selection.c | 13 - drivers/tty/vt/vt.c| 2 -- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 145cf969d3ae..1c31746f9f5e 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -157,7 +157,7 @@ static int store_utf8(u16 c, char *p) * The entire selection process is managed under the console_lock. It's * a lot under the lock but its hardly a performance path */ -int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) +static int __set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; int sel_mode, new_sel_start, new_sel_end, spc; @@ -333,6 +333,17 @@ unlock: return ret; } +int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) +{ + int ret; + + console_lock(); + ret = __set_selection(sel, tty); + console_unlock(); + + return ret; +} + /* Insert the contents of the selection buffer into the * queue of the tty associated with the current console. * Invoked by ioctl(). diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 795d7867ac24..07078cfa2524 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2603,9 +2603,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) switch (type) { case TIOCL_SETSEL: - console_lock(); ret = set_selection((struct tiocl_selection __user *)(p+1), tty); - console_unlock(); break; case TIOCL_PASTESEL: ret = paste_selection(tty); -- 2.27.0 ___ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel
[Devel] [PATCH vz8] mm/memcg: Use per-cpu stock charges for ->kmem and ->cache counters
Currently we use per-cpu stocks to do precharges of the ->memory and ->memsw counters. Do this for the ->kmem and ->cache as well to decrease contention on these counters as well. https://jira.sw.ru/browse/PSBM-101300 Signed-off-by: Andrey Ryabinin --- mm/memcontrol.c | 75 + 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 134cb27307f2..b3f97309ca39 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2023,6 +2023,8 @@ EXPORT_SYMBOL(unlock_page_memcg); struct memcg_stock_pcp { struct mem_cgroup *cached; /* this never be root cgroup */ unsigned int nr_pages; + unsigned int cache_nr_pages; + unsigned int kmem_nr_pages; struct work_struct work; unsigned long flags; #define FLUSHING_CACHED_CHARGE 0 @@ -2041,7 +2043,8 @@ static DEFINE_MUTEX(percpu_charge_mutex); * * returns true if successful, false otherwise. */ -static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) +static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages, + bool cache, bool kmem) { struct memcg_stock_pcp *stock; unsigned long flags; @@ -2053,9 +2056,19 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) local_irq_save(flags); stock = this_cpu_ptr(&memcg_stock); - if (memcg == stock->cached && stock->nr_pages >= nr_pages) { - stock->nr_pages -= nr_pages; - ret = true; + if (memcg == stock->cached) { + if (cache && stock->cache_nr_pages >= nr_pages) { + stock->cache_nr_pages -= nr_pages; + ret = true; + } + if (kmem && stock->kmem_nr_pages >= nr_pages) { + stock->kmem_nr_pages -= nr_pages; + ret = true; + } + if (!cache && !kmem && stock->nr_pages >= nr_pages) { + stock->nr_pages -= nr_pages; + ret = true; + } } local_irq_restore(flags); @@ -2069,13 +2082,21 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) static void drain_stock(struct memcg_stock_pcp *stock) { struct mem_cgroup *old = stock->cached; + unsigned long nr_pages = stock->nr_pages + stock->cache_nr_pages + stock->kmem_nr_pages; + + if (stock->cache_nr_pages) + page_counter_uncharge(&old->cache, stock->cache_nr_pages); + if (stock->kmem_nr_pages) + page_counter_uncharge(&old->kmem, stock->kmem_nr_pages); - if (stock->nr_pages) { - page_counter_uncharge(&old->memory, stock->nr_pages); + if (nr_pages) { + page_counter_uncharge(&old->memory, nr_pages); if (do_memsw_account()) - page_counter_uncharge(&old->memsw, stock->nr_pages); + page_counter_uncharge(&old->memsw, nr_pages); css_put_many(&old->css, stock->nr_pages); stock->nr_pages = 0; + stock->kmem_nr_pages = 0; + stock->cache_nr_pages = 0; } stock->cached = NULL; } @@ -2102,10 +2123,12 @@ static void drain_local_stock(struct work_struct *dummy) * Cache charges(val) to local per_cpu area. * This will be consumed by consume_stock() function, later. */ -static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) +static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages, + bool cache, bool kmem) { struct memcg_stock_pcp *stock; unsigned long flags; + unsigned long stock_nr_pages; local_irq_save(flags); @@ -2114,9 +2137,17 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) drain_stock(stock); stock->cached = memcg; } - stock->nr_pages += nr_pages; - if (stock->nr_pages > MEMCG_CHARGE_BATCH) + if (cache) + stock->cache_nr_pages += nr_pages; + else if (kmem) + stock->kmem_nr_pages += nr_pages; + else + stock->nr_pages += nr_pages; + + stock_nr_pages = stock->nr_pages + stock->cache_nr_pages + + stock->kmem_nr_pages; + if (nr_pages > MEMCG_CHARGE_BATCH) drain_stock(stock); local_irq_restore(flags); @@ -2143,9 +2174,11 @@ static void drain_all_stock(struct mem_cgroup *root_memcg) for_each_online_cpu(cpu) { struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu); struct mem_cgroup *memcg; + unsigned long nr_pages = stock->nr_pages + stock->kmem_nr_pages + + stock->cache_nr_pages; memcg = stock->cached; - if (!memcg || !stock->nr_pages || !cs