+++ /dev/null
-From 62a6cfddcc0a5313e7da3e8311ba16226fe0ac10 Mon Sep 17 00:00:00 2001
-From: Sachin Prabhu <sprabhu@redhat.com>
-Date: Sun, 16 Apr 2017 20:37:24 +0100
-Subject: cifs: Do not send echoes before Negotiate is complete
-
-From: Sachin Prabhu <sprabhu@redhat.com>
-
-commit 62a6cfddcc0a5313e7da3e8311ba16226fe0ac10 upstream.
-
-commit 4fcd1813e640 ("Fix reconnect to not defer smb3 session reconnect
-long after socket reconnect") added support for Negotiate requests to
-be initiated by echo calls.
-
-To avoid delays in calling echo after a reconnect, I added the patch
-introduced by the commit b8c600120fc8 ("Call echo service immediately
-after socket reconnect").
-
-This has however caused a regression with cifs shares which do not have
-support for echo calls to trigger Negotiate requests. On connections
-which need to call Negotiation, the echo calls trigger an error which
-triggers a reconnect which in turn triggers another echo call. This
-results in a loop which is only broken when an operation is performed on
-the cifs share. For an idle share, it can DOS a server.
-
-The patch uses the smb_operation can_echo() for cifs so that it is
-called only if connection has been already been setup.
-
-kernel bz: 194531
-
-Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
-Tested-by: Jonathan Liu <net147@gmail.com>
-Acked-by: Pavel Shilovsky <pshilov@microsoft.com>
-Signed-off-by: Steve French <smfrench@gmail.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- fs/cifs/smb1ops.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/fs/cifs/smb1ops.c
-+++ b/fs/cifs/smb1ops.c
-@@ -1014,6 +1014,15 @@ cifs_dir_needs_close(struct cifsFileInfo
- return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
- }
-
-+static bool
-+cifs_can_echo(struct TCP_Server_Info *server)
-+{
-+ if (server->tcpStatus == CifsGood)
-+ return true;
-+
-+ return false;
-+}
-+
- struct smb_version_operations smb1_operations = {
- .send_cancel = send_nt_cancel,
- .compare_fids = cifs_compare_fids,
-@@ -1048,6 +1057,7 @@ struct smb_version_operations smb1_opera
- .get_dfs_refer = CIFSGetDFSRefer,
- .qfs_tcon = cifs_qfs_tcon,
- .is_path_accessible = cifs_is_path_accessible,
-+ .can_echo = cifs_can_echo,
- .query_path_info = cifs_query_path_info,
- .query_file_info = cifs_query_file_info,
- .get_srv_inum = cifs_get_srv_inum,
+++ /dev/null
-From a0918f1ce6a43ac980b42b300ec443c154970979 Mon Sep 17 00:00:00 2001
-From: Germano Percossi <germano.percossi@citrix.com>
-Date: Fri, 7 Apr 2017 12:29:37 +0100
-Subject: CIFS: remove bad_network_name flag
-
-From: Germano Percossi <germano.percossi@citrix.com>
-
-commit a0918f1ce6a43ac980b42b300ec443c154970979 upstream.
-
-STATUS_BAD_NETWORK_NAME can be received during node failover,
-causing the flag to be set and making the reconnect thread
-always unsuccessful, thereafter.
-
-Once the only place where it is set is removed, the remaining
-bits are rendered moot.
-
-Removing it does not prevent "mount" from failing when a non
-existent share is passed.
-
-What happens when the share really ceases to exist while the
-share is mounted is undefined now as much as it was before.
-
-Signed-off-by: Germano Percossi <germano.percossi@citrix.com>
-Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
-Signed-off-by: Steve French <smfrench@gmail.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- fs/cifs/cifsglob.h | 1 -
- fs/cifs/smb2pdu.c | 5 -----
- 2 files changed, 6 deletions(-)
-
---- a/fs/cifs/cifsglob.h
-+++ b/fs/cifs/cifsglob.h
-@@ -891,7 +891,6 @@ struct cifs_tcon {
- bool need_reconnect:1; /* connection reset, tid now invalid */
- #ifdef CONFIG_CIFS_SMB2
- bool print:1; /* set if connection to printer share */
-- bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
- __le32 capabilities;
- __u32 share_flags;
- __u32 maximal_access;
---- a/fs/cifs/smb2pdu.c
-+++ b/fs/cifs/smb2pdu.c
-@@ -854,9 +854,6 @@ SMB2_tcon(const unsigned int xid, struct
- else
- return -EIO;
-
-- if (tcon && tcon->bad_network_name)
-- return -ENOENT;
--
- unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
- if (unc_path == NULL)
- return -ENOMEM;
-@@ -950,8 +947,6 @@ tcon_exit:
- tcon_error_exit:
- if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
- cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
-- if (tcon)
-- tcon->bad_network_name = true;
- }
- goto tcon_exit;
- }
+++ /dev/null
-From c1644fe041ebaf6519f6809146a77c3ead9193af Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Tue, 18 Apr 2017 15:31:08 +0100
-Subject: KEYS: Change the name of the dead type to ".dead" to prevent user access
-
-From: David Howells <dhowells@redhat.com>
-
-commit c1644fe041ebaf6519f6809146a77c3ead9193af upstream.
-
-This fixes CVE-2017-6951.
-
-Userspace should not be able to do things with the "dead" key type as it
-doesn't have some of the helper functions set upon it that the kernel
-needs. Attempting to use it may cause the kernel to crash.
-
-Fix this by changing the name of the type to ".dead" so that it's rejected
-up front on userspace syscalls by key_get_type_from_user().
-
-Though this doesn't seem to affect recent kernels, it does affect older
-ones, certainly those prior to:
-
- commit c06cfb08b88dfbe13be44a69ae2fdc3a7c902d81
- Author: David Howells <dhowells@redhat.com>
- Date: Tue Sep 16 17:36:06 2014 +0100
- KEYS: Remove key_type::match in favour of overriding default by match_preparse
-
-which went in before 3.18-rc1.
-
-Signed-off-by: David Howells <dhowells@redhat.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- security/keys/gc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/security/keys/gc.c
-+++ b/security/keys/gc.c
-@@ -46,7 +46,7 @@ static unsigned long key_gc_flags;
- * immediately unlinked.
- */
- struct key_type key_type_dead = {
-- .name = "dead",
-+ .name = ".dead",
- };
-
- /*
+++ /dev/null
-From ee8f844e3c5a73b999edf733df1c529d6503ec2f Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Tue, 18 Apr 2017 15:31:07 +0100
-Subject: KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings
-
-From: David Howells <dhowells@redhat.com>
-
-commit ee8f844e3c5a73b999edf733df1c529d6503ec2f upstream.
-
-This fixes CVE-2016-9604.
-
-Keyrings whose name begin with a '.' are special internal keyrings and so
-userspace isn't allowed to create keyrings by this name to prevent
-shadowing. However, the patch that added the guard didn't fix
-KEYCTL_JOIN_SESSION_KEYRING. Not only can that create dot-named keyrings,
-it can also subscribe to them as a session keyring if they grant SEARCH
-permission to the user.
-
-This, for example, allows a root process to set .builtin_trusted_keys as
-its session keyring, at which point it has full access because now the
-possessor permissions are added. This permits root to add extra public
-keys, thereby bypassing module verification.
-
-This also affects kexec and IMA.
-
-This can be tested by (as root):
-
- keyctl session .builtin_trusted_keys
- keyctl add user a a @s
- keyctl list @s
-
-which on my test box gives me:
-
- 2 keys in keyring:
- 180010936: ---lswrv 0 0 asymmetric: Build time autogenerated kernel key: ae3d4a31b82daa8e1a75b49dc2bba949fd992a05
- 801382539: --alswrv 0 0 user: a
-
-
-Fix this by rejecting names beginning with a '.' in the keyctl.
-
-Signed-off-by: David Howells <dhowells@redhat.com>
-Acked-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
-cc: linux-ima-devel@lists.sourceforge.net
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- security/keys/keyctl.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
---- a/security/keys/keyctl.c
-+++ b/security/keys/keyctl.c
-@@ -277,7 +277,8 @@ error:
- * Create and join an anonymous session keyring or join a named session
- * keyring, creating it if necessary. A named session keyring must have Search
- * permission for it to be joined. Session keyrings without this permit will
-- * be skipped over.
-+ * be skipped over. It is not permitted for userspace to create or join
-+ * keyrings whose name begin with a dot.
- *
- * If successful, the ID of the joined session keyring will be returned.
- */
-@@ -294,12 +295,16 @@ long keyctl_join_session_keyring(const c
- ret = PTR_ERR(name);
- goto error;
- }
-+
-+ ret = -EPERM;
-+ if (name[0] == '.')
-+ goto error_name;
- }
-
- /* join the session */
- ret = join_session_keyring(name);
-+error_name:
- kfree(name);
--
- error:
- return ret;
- }
+++ /dev/null
-From c9f838d104fed6f2f61d68164712e3204bf5271b Mon Sep 17 00:00:00 2001
-From: Eric Biggers <ebiggers@google.com>
-Date: Tue, 18 Apr 2017 15:31:09 +0100
-Subject: KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings
-
-From: Eric Biggers <ebiggers@google.com>
-
-commit c9f838d104fed6f2f61d68164712e3204bf5271b upstream.
-
-This fixes CVE-2017-7472.
-
-Running the following program as an unprivileged user exhausts kernel
-memory by leaking thread keyrings:
-
- #include <keyutils.h>
-
- int main()
- {
- for (;;)
- keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_THREAD_KEYRING);
- }
-
-Fix it by only creating a new thread keyring if there wasn't one before.
-To make things more consistent, make install_thread_keyring_to_cred()
-and install_process_keyring_to_cred() both return 0 if the corresponding
-keyring is already present.
-
-Fixes: d84f4f992cbd ("CRED: Inaugurate COW credentials")
-Signed-off-by: Eric Biggers <ebiggers@google.com>
-Signed-off-by: David Howells <dhowells@redhat.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- security/keys/keyctl.c | 11 +++-------
- security/keys/process_keys.c | 44 ++++++++++++++++++++++++++-----------------
- 2 files changed, 31 insertions(+), 24 deletions(-)
-
---- a/security/keys/keyctl.c
-+++ b/security/keys/keyctl.c
-@@ -1258,8 +1258,8 @@ error:
- * Read or set the default keyring in which request_key() will cache keys and
- * return the old setting.
- *
-- * If a process keyring is specified then this will be created if it doesn't
-- * yet exist. The old setting will be returned if successful.
-+ * If a thread or process keyring is specified then it will be created if it
-+ * doesn't yet exist. The old setting will be returned if successful.
- */
- long keyctl_set_reqkey_keyring(int reqkey_defl)
- {
-@@ -1284,11 +1284,8 @@ long keyctl_set_reqkey_keyring(int reqke
-
- case KEY_REQKEY_DEFL_PROCESS_KEYRING:
- ret = install_process_keyring_to_cred(new);
-- if (ret < 0) {
-- if (ret != -EEXIST)
-- goto error;
-- ret = 0;
-- }
-+ if (ret < 0)
-+ goto error;
- goto set;
-
- case KEY_REQKEY_DEFL_DEFAULT:
---- a/security/keys/process_keys.c
-+++ b/security/keys/process_keys.c
-@@ -125,13 +125,18 @@ error:
- }
-
- /*
-- * Install a fresh thread keyring directly to new credentials. This keyring is
-- * allowed to overrun the quota.
-+ * Install a thread keyring to the given credentials struct if it didn't have
-+ * one already. This is allowed to overrun the quota.
-+ *
-+ * Return: 0 if a thread keyring is now present; -errno on failure.
- */
- int install_thread_keyring_to_cred(struct cred *new)
- {
- struct key *keyring;
-
-+ if (new->thread_keyring)
-+ return 0;
-+
- keyring = keyring_alloc("_tid", new->uid, new->gid, new,
- KEY_POS_ALL | KEY_USR_VIEW,
- KEY_ALLOC_QUOTA_OVERRUN, NULL);
-@@ -143,7 +148,9 @@ int install_thread_keyring_to_cred(struc
- }
-
- /*
-- * Install a fresh thread keyring, discarding the old one.
-+ * Install a thread keyring to the current task if it didn't have one already.
-+ *
-+ * Return: 0 if a thread keyring is now present; -errno on failure.
- */
- static int install_thread_keyring(void)
- {
-@@ -154,8 +161,6 @@ static int install_thread_keyring(void)
- if (!new)
- return -ENOMEM;
-
-- BUG_ON(new->thread_keyring);
--
- ret = install_thread_keyring_to_cred(new);
- if (ret < 0) {
- abort_creds(new);
-@@ -166,17 +171,17 @@ static int install_thread_keyring(void)
- }
-
- /*
-- * Install a process keyring directly to a credentials struct.
-+ * Install a process keyring to the given credentials struct if it didn't have
-+ * one already. This is allowed to overrun the quota.
- *
-- * Returns -EEXIST if there was already a process keyring, 0 if one installed,
-- * and other value on any other error
-+ * Return: 0 if a process keyring is now present; -errno on failure.
- */
- int install_process_keyring_to_cred(struct cred *new)
- {
- struct key *keyring;
-
- if (new->process_keyring)
-- return -EEXIST;
-+ return 0;
-
- keyring = keyring_alloc("_pid", new->uid, new->gid, new,
- KEY_POS_ALL | KEY_USR_VIEW,
-@@ -189,11 +194,9 @@ int install_process_keyring_to_cred(stru
- }
-
- /*
-- * Make sure a process keyring is installed for the current process. The
-- * existing process keyring is not replaced.
-+ * Install a process keyring to the current task if it didn't have one already.
- *
-- * Returns 0 if there is a process keyring by the end of this function, some
-- * error otherwise.
-+ * Return: 0 if a process keyring is now present; -errno on failure.
- */
- static int install_process_keyring(void)
- {
-@@ -207,14 +210,18 @@ static int install_process_keyring(void)
- ret = install_process_keyring_to_cred(new);
- if (ret < 0) {
- abort_creds(new);
-- return ret != -EEXIST ? ret : 0;
-+ return ret;
- }
-
- return commit_creds(new);
- }
-
- /*
-- * Install a session keyring directly to a credentials struct.
-+ * Install the given keyring as the session keyring of the given credentials
-+ * struct, replacing the existing one if any. If the given keyring is NULL,
-+ * then install a new anonymous session keyring.
-+ *
-+ * Return: 0 on success; -errno on failure.
- */
- int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
- {
-@@ -249,8 +256,11 @@ int install_session_keyring_to_cred(stru
- }
-
- /*
-- * Install a session keyring, discarding the old one. If a keyring is not
-- * supplied, an empty one is invented.
-+ * Install the given keyring as the session keyring of the current task,
-+ * replacing the existing one if any. If the given keyring is NULL, then
-+ * install a new anonymous session keyring.
-+ *
-+ * Return: 0 on success; -errno on failure.
- */
- static int install_session_keyring(struct key *keyring)
- {
+++ /dev/null
-From 78f7a45dac2a2d2002f98a3a95f7979867868d73 Mon Sep 17 00:00:00 2001
-From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
-Date: Wed, 19 Apr 2017 14:29:46 -0400
-Subject: ring-buffer: Have ring_buffer_iter_empty() return true when empty
-
-From: Steven Rostedt (VMware) <rostedt@goodmis.org>
-
-commit 78f7a45dac2a2d2002f98a3a95f7979867868d73 upstream.
-
-I noticed that reading the snapshot file when it is empty no longer gives a
-status. It suppose to show the status of the snapshot buffer as well as how
-to allocate and use it. For example:
-
- ># cat snapshot
- # tracer: nop
- #
- #
- # * Snapshot is allocated *
- #
- # Snapshot commands:
- # echo 0 > snapshot : Clears and frees snapshot buffer
- # echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.
- # Takes a snapshot of the main buffer.
- # echo 2 > snapshot : Clears snapshot buffer (but does not allocate or free)
- # (Doesn't have to be '2' works with any number that
- # is not a '0' or '1')
-
-But instead it just showed an empty buffer:
-
- ># cat snapshot
- # tracer: nop
- #
- # entries-in-buffer/entries-written: 0/0 #P:4
- #
- # _-----=> irqs-off
- # / _----=> need-resched
- # | / _---=> hardirq/softirq
- # || / _--=> preempt-depth
- # ||| / delay
- # TASK-PID CPU# |||| TIMESTAMP FUNCTION
- # | | | |||| | |
-
-What happened was that it was using the ring_buffer_iter_empty() function to
-see if it was empty, and if it was, it showed the status. But that function
-was returning false when it was empty. The reason was that the iter header
-page was on the reader page, and the reader page was empty, but so was the
-buffer itself. The check only tested to see if the iter was on the commit
-page, but the commit page was no longer pointing to the reader page, but as
-all pages were empty, the buffer is also.
-
-Fixes: 651e22f2701b ("ring-buffer: Always reset iterator to reader page")
-Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- kernel/trace/ring_buffer.c | 16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
-
---- a/kernel/trace/ring_buffer.c
-+++ b/kernel/trace/ring_buffer.c
-@@ -3451,11 +3451,23 @@ EXPORT_SYMBOL_GPL(ring_buffer_iter_reset
- int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
- {
- struct ring_buffer_per_cpu *cpu_buffer;
-+ struct buffer_page *reader;
-+ struct buffer_page *head_page;
-+ struct buffer_page *commit_page;
-+ unsigned commit;
-
- cpu_buffer = iter->cpu_buffer;
-
-- return iter->head_page == cpu_buffer->commit_page &&
-- iter->head == rb_commit_index(cpu_buffer);
-+ /* Remember, trace recording is off when iterator is in use */
-+ reader = cpu_buffer->reader_page;
-+ head_page = cpu_buffer->head_page;
-+ commit_page = cpu_buffer->commit_page;
-+ commit = rb_page_commit(commit_page);
-+
-+ return ((iter->head_page == commit_page && iter->head == commit) ||
-+ (iter->head_page == reader && commit_page == head_page &&
-+ head_page->read == commit &&
-+ iter->head == rb_page_commit(cpu_buffer->reader_page)));
- }
- EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
-
+++ /dev/null
-From a8f60d1fadf7b8b54449fcc9d6b15248917478ba Mon Sep 17 00:00:00 2001
-From: Christian Borntraeger <borntraeger@de.ibm.com>
-Date: Sun, 9 Apr 2017 22:09:38 +0200
-Subject: s390/mm: fix CMMA vs KSM vs others
-
-From: Christian Borntraeger <borntraeger@de.ibm.com>
-
-commit a8f60d1fadf7b8b54449fcc9d6b15248917478ba upstream.
-
-On heavy paging with KSM I see guest data corruption. Turns out that
-KSM will add pages to its tree, where the mapping return true for
-pte_unused (or might become as such later). KSM will unmap such pages
-and reinstantiate with different attributes (e.g. write protected or
-special, e.g. in replace_page or write_protect_page)). This uncovered
-a bug in our pagetable handling: We must remove the unused flag as
-soon as an entry becomes present again.
-
-Signed-of-by: Christian Borntraeger <borntraeger@de.ibm.com>
-Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
-
-diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
-index 024f85f..e2c0e4e 100644
---- a/arch/s390/include/asm/pgtable.h
-+++ b/arch/s390/include/asm/pgtable.h
-@@ -829,6 +829,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
- {
- pgste_t pgste;
-
-+ if (pte_present(entry))
-+ pte_val(entry) &= ~_PAGE_UNUSED;
- if (mm_has_pgste(mm)) {
- pgste = pgste_get_lock(ptep);
- pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
---
-2.7.4
+++ /dev/null
-keys-disallow-keyrings-beginning-with-.-to-be-joined-as-session-keyrings.patch
-keys-change-the-name-of-the-dead-type-to-.dead-to-prevent-user-access.patch
-keys-fix-keyctl_set_reqkey_keyring-to-not-leak-thread-keyrings.patch
-tracing-allocate-the-snapshot-buffer-before-enabling-probe.patch
-ring-buffer-have-ring_buffer_iter_empty-return-true-when-empty.patch
-cifs-do-not-send-echoes-before-negotiate-is-complete.patch
-cifs-remove-bad_network_name-flag.patch
-s390-mm-fix-cmma-vs-ksm-vs-others.patch
-
+++ /dev/null
-From df62db5be2e5f070ecd1a5ece5945b590ee112e0 Mon Sep 17 00:00:00 2001
-From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>
-Date: Wed, 19 Apr 2017 12:07:08 -0400
-Subject: tracing: Allocate the snapshot buffer before enabling probe
-
-From: Steven Rostedt (VMware) <rostedt@goodmis.org>
-
-commit df62db5be2e5f070ecd1a5ece5945b590ee112e0 upstream.
-
-Currently the snapshot trigger enables the probe and then allocates the
-snapshot. If the probe triggers before the allocation, it could cause the
-snapshot to fail and turn tracing off. It's best to allocate the snapshot
-buffer first, and then enable the trigger. If something goes wrong in the
-enabling of the trigger, the snapshot buffer is still allocated, but it can
-also be freed by the user by writting zero into the snapshot buffer file.
-
-Also add a check of the return status of alloc_snapshot().
-
-Fixes: 77fd5c15e3 ("tracing: Add snapshot trigger to function probes")
-Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- kernel/trace/trace.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/kernel/trace/trace.c
-+++ b/kernel/trace/trace.c
-@@ -5809,11 +5809,13 @@ ftrace_trace_snapshot_callback(struct ft
- return ret;
-
- out_reg:
-- ret = register_ftrace_function_probe(glob, ops, count);
-+ ret = alloc_snapshot(&global_trace);
-+ if (ret < 0)
-+ goto out;
-
-- if (ret >= 0)
-- alloc_snapshot(&global_trace);
-+ ret = register_ftrace_function_probe(glob, ops, count);
-
-+ out:
- return ret < 0 ? ret : 0;
- }
-