From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id E4F2CC8303C for ; Sat, 5 Jul 2025 21:54:18 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 4FD0A6B03F7; Sat, 5 Jul 2025 17:54:18 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 4AD546B03F8; Sat, 5 Jul 2025 17:54:18 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3C3116B03F9; Sat, 5 Jul 2025 17:54:18 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 27DC26B03F7 for ; Sat, 5 Jul 2025 17:54:18 -0400 (EDT) Received: from smtpin06.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 90217140FEF for ; Sat, 5 Jul 2025 21:54:17 +0000 (UTC) X-FDA: 83631564954.06.4D9D128 Received: from nyc.source.kernel.org (nyc.source.kernel.org [147.75.193.91]) by imf09.hostedemail.com (Postfix) with ESMTP id 06500140007 for ; Sat, 5 Jul 2025 21:54:15 +0000 (UTC) Authentication-Results: imf09.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=eXdYW4Qn; spf=pass (imf09.hostedemail.com: domain of alx@kernel.org designates 147.75.193.91 as permitted sender) smtp.mailfrom=alx@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1751752456; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=+XXdPz5ZEWJMhSE2KloZwsxwNzOwx+M88hkSG0TXMsI=; b=Ds/yKEVGX1am/njgTOqRiNjlAloF+YcBsA54kR4pfS7OlpeB6sh9Er1VJ3aRjRYEpysjJn HHNkPihQOlG3SEBz4Tynz94OEwb8O/q5xDG4L271Za6da17RJb0TRNHstp7/qYkiGCClq+ EGEAiPHNnm6oaB7Kf8d9sQhwcMAbO2w= ARC-Authentication-Results: i=1; imf09.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=eXdYW4Qn; spf=pass (imf09.hostedemail.com: domain of alx@kernel.org designates 147.75.193.91 as permitted sender) smtp.mailfrom=alx@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1751752456; a=rsa-sha256; cv=none; b=SBET05PKy2d706rqlmfQXy50elABUFxVD5XsaNmO5tqua70STSjrErTcgh44K8l3vbFvJl PqtHkfm0PS1IRaibfngzgOpjjcXKCxBRKm7vie9dNzUQPH30TwqSQwLjpGiO3MNZsz2IWf b3uQeXzzy3qv/FgTcsa0XZBJSpTN+HM= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by nyc.source.kernel.org (Postfix) with ESMTP id 0BF24A53998; Sat, 5 Jul 2025 21:54:10 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 60E33C4CEE7; Sat, 5 Jul 2025 21:54:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1751752449; bh=s/yRBKu6UqcUan3ODZyzQSqwzumftBUBlBaea3zaHwc=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=eXdYW4Qnu95vJga3qYboCnqtZY6vmfnuKPGpjIFcKzXKGoD7uCfZ0eq6qLLL8gaTH rA34MD36JLD/eTurwbX0qAEL+ZP+8ZH05mGu7K61X+MIXUwhmjoi2Lbo67er8enxJK YhUoA8w76nIZZbU09Z6j8m5NBExjNGYZuEyXfDjGqD8UTLVyO3FB3PflVaiBkc4jlh cs2kqIBNyY/cQgRN18DU2KfcKj3UCzEZ7pjGvSyrKZ7xBGXuRYD2h1RrpF2eqgyuS8 b+5G16yxfq7l4ft30CX13Pu8yrZg2TEDRkM/oNGYhVJGfJZ3v6n5uvSvKmWpEfLiu4 4oysRZ+fQZyIA== Date: Sat, 5 Jul 2025 23:54:07 +0200 From: Alejandro Colomar To: linux-mm@kvack.org, linux-hardening@vger.kernel.org Cc: Kees Cook , Christopher Bazley , shadow <~hallyn/shadow@lists.sr.ht>, linux-kernel@vger.kernel.org, Andrew Morton , kasan-dev@googlegroups.com, Dmitry Vyukov , Alexander Potapenko , Marco Elver , Christoph Lameter , David Rientjes , Vlastimil Babka , Roman Gushchin , Harry Yoo Subject: Re: [RFC v1 3/3] mm: Use seprintf() instead of less ergonomic APIs Message-ID: References: MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="sxjq76zh675ubdos" Content-Disposition: inline In-Reply-To: X-Stat-Signature: hfwuzw57efqg91xwkxh5frytng9ug6pj X-Rspamd-Queue-Id: 06500140007 X-Rspamd-Server: rspam11 X-Rspam-User: X-HE-Tag: 1751752455-481954 X-HE-Meta: U2FsdGVkX19rAGeLu07I6yOQd8jxK4qHDNi7TWBdKxgA9Vbc5dh8Q+d+fHny4Rcq3QSLVWyp3hmyLmYQSih2+rQ861uYpsijcbH29FbPd9wosaZrKwjps3YUdNbQmI09qqxF54DSI/KZLmMGnEFPkQBWojGK9/MPYOFd9bGmoYR2XEaXsm7bOKoEw1y7Ndv5BzlhnE+0Pd9PfecB6CnH8JNoWPWqCb8kV0CLEsY8tS/dp3OL9gZWWiN1CLg+3HaAfYY/py2f62kney15IWxdm1CZpvdb9w6hSSnIvhyLBDrkE76lHuUpNpQLQV4D1c3Nq11jZS0MK7tCRZ3RYVtAvhOV61MRu8e7m0gLaJFZ2xlVZJM8inPLHMyN1vflqF8+ClS+1r4VsCd8tMjdM3FYWNMJdZk32JUJ0mEvJAJNS1sHemQ29l3vhLQQKLsuf4Lf6TgMikCPuegrTE4HONeAHQW3/TrjYwn2bIttn7cx0zSFAgHQopB7D1jIwxzYcdE6ynfV7yphTTUrpXr9TyoLEpy2OUdMzy+HdfD4EJkktwpDY4eEpr5g0YU+t4ZhaXIk37bF9QF1hzvO1zydZ0pXSNpJaml4ivD15xHXQvKc6u5YlCzatUEqN4pDjm6+/OzXdhojIq6AW8+P8fEYBDlTQKWomF1yDHQSvLgvhJ9U0+UwQVT8btSkofbw9/XGSjYZ/Mj97onoiJmDOIusxuUhQaJK019ZHB8Tb5Qg+vfWud85CgbYmmG/A8Efzo96WojhPuqZCxzOjN4m4Rt5XtIFit2ZjFEAzTCaY4CgfsO+jPVME9V9cvoNbCpeDtDaoZDZMZTU1hcmKpgUoQ03/hZ2O/NyAJ36Q28L4u5hHLnPMDb2/t6ZFTA37IhbLbiEyOY/fkh7qG9uP4LkTOD8ZEVswUt8lzJPtz9tMHlD4IZf70By00dvPl5kRa9JPzImDm5upDdSWdtlYBKe7WsAhuC Q29u0TlC +sCUUcOuHo6go1QxAC78bgjNu1U1yXiLTO4yKm4Gfi1aBPcAQByCMU8T2Y8w1BwSlbCipqIin9g3E1fo6qQ5GG7vy3w== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: --sxjq76zh675ubdos Content-Type: text/plain; protected-headers=v1; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable From: Alejandro Colomar To: linux-mm@kvack.org, linux-hardening@vger.kernel.org Cc: Kees Cook , Christopher Bazley , shadow <~hallyn/shadow@lists.sr.ht>, linux-kernel@vger.kernel.org, Andrew Morton , kasan-dev@googlegroups.com, Dmitry Vyukov , Alexander Potapenko , Marco Elver , Christoph Lameter , David Rientjes , Vlastimil Babka , Roman Gushchin , Harry Yoo Subject: Re: [RFC v1 3/3] mm: Use seprintf() instead of less ergonomic APIs References: MIME-Version: 1.0 In-Reply-To: On Sat, Jul 05, 2025 at 10:33:53PM +0200, Alejandro Colomar wrote: > While doing this, I detected some anomalies in the existing code: >=20 > mm/kfence/kfence_test.c: >=20 > The last call to scnprintf() did increment 'cur', but it's > unused after that, so it was dead code. I've removed the dead > code in this patch. >=20 > mm/mempolicy.c: >=20 > This file uses the 'p +=3D snprintf()' anti-pattern. That will > overflow the pointer on truncation, which has undefined > behavior. Using seprintf(), this bug is fixed. >=20 > As in the previous file, here there was also dead code in the > last scnprintf() call, by incrementing a pointer that is not > used after the call. I've removed the dead code. >=20 > mm/page_owner.c: >=20 > Within print_page_owner(), there are some calls to scnprintf(), > which do report truncation. And then there are other calls to This is a typo; I meant s/do/don't/ > snprintf(), where we handle errors (there are two 'goto err'). >=20 > I've kept the existing error handling, as I trust it's there for > a good reason (i.e., we may want to avoid calling > print_page_owner_memcg() if we truncated before). Please review > if this amount of error handling is the right one, or if we want > to add or remove some. For seprintf(), a single test for null > after the last call is enough to detect truncation. >=20 > mm/slub.c: >=20 > Again, the 'p +=3D snprintf()' anti-pattern. This is UB, and by > using seprintf() we've fixed the bug. >=20 > Cc: Kees Cook > Cc: Christopher Bazley > Signed-off-by: Alejandro Colomar > --- > mm/kfence/kfence_test.c | 24 ++++++++++++------------ > mm/kmsan/kmsan_test.c | 4 ++-- > mm/mempolicy.c | 18 +++++++++--------- > mm/page_owner.c | 32 +++++++++++++++++--------------- > mm/slub.c | 5 +++-- > 5 files changed, 43 insertions(+), 40 deletions(-) >=20 > diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c > index 00034e37bc9f..ff734c514c03 100644 > --- a/mm/kfence/kfence_test.c > +++ b/mm/kfence/kfence_test.c > @@ -113,26 +113,26 @@ static bool report_matches(const struct expect_repo= rt *r) > end =3D &expect[0][sizeof(expect[0]) - 1]; > switch (r->type) { > case KFENCE_ERROR_OOB: > - cur +=3D scnprintf(cur, end - cur, "BUG: KFENCE: out-of-bounds %s", > + cur =3D seprintf(cur, end, "BUG: KFENCE: out-of-bounds %s", > get_access_type(r)); > break; > case KFENCE_ERROR_UAF: > - cur +=3D scnprintf(cur, end - cur, "BUG: KFENCE: use-after-free %s", > + cur =3D seprintf(cur, end, "BUG: KFENCE: use-after-free %s", > get_access_type(r)); > break; > case KFENCE_ERROR_CORRUPTION: > - cur +=3D scnprintf(cur, end - cur, "BUG: KFENCE: memory corruption"); > + cur =3D seprintf(cur, end, "BUG: KFENCE: memory corruption"); > break; > case KFENCE_ERROR_INVALID: > - cur +=3D scnprintf(cur, end - cur, "BUG: KFENCE: invalid %s", > + cur =3D seprintf(cur, end, "BUG: KFENCE: invalid %s", > get_access_type(r)); > break; > case KFENCE_ERROR_INVALID_FREE: > - cur +=3D scnprintf(cur, end - cur, "BUG: KFENCE: invalid free"); > + cur =3D seprintf(cur, end, "BUG: KFENCE: invalid free"); > break; > } > =20 > - scnprintf(cur, end - cur, " in %pS", r->fn); > + seprintf(cur, end, " in %pS", r->fn); > /* The exact offset won't match, remove it; also strip module name. */ > cur =3D strchr(expect[0], '+'); > if (cur) > @@ -144,26 +144,26 @@ static bool report_matches(const struct expect_repo= rt *r) > =20 > switch (r->type) { > case KFENCE_ERROR_OOB: > - cur +=3D scnprintf(cur, end - cur, "Out-of-bounds %s at", get_access_t= ype(r)); > + cur =3D seprintf(cur, end, "Out-of-bounds %s at", get_access_type(r)); > addr =3D arch_kfence_test_address(addr); > break; > case KFENCE_ERROR_UAF: > - cur +=3D scnprintf(cur, end - cur, "Use-after-free %s at", get_access_= type(r)); > + cur =3D seprintf(cur, end, "Use-after-free %s at", get_access_type(r)); > addr =3D arch_kfence_test_address(addr); > break; > case KFENCE_ERROR_CORRUPTION: > - cur +=3D scnprintf(cur, end - cur, "Corrupted memory at"); > + cur =3D seprintf(cur, end, "Corrupted memory at"); > break; > case KFENCE_ERROR_INVALID: > - cur +=3D scnprintf(cur, end - cur, "Invalid %s at", get_access_type(r)= ); > + cur =3D seprintf(cur, end, "Invalid %s at", get_access_type(r)); > addr =3D arch_kfence_test_address(addr); > break; > case KFENCE_ERROR_INVALID_FREE: > - cur +=3D scnprintf(cur, end - cur, "Invalid free of"); > + cur =3D seprintf(cur, end, "Invalid free of"); > break; > } > =20 > - cur +=3D scnprintf(cur, end - cur, " 0x%p", (void *)addr); > + seprintf(cur, end, " 0x%p", (void *)addr); > =20 > spin_lock_irqsave(&observed.lock, flags); > if (!report_available()) > diff --git a/mm/kmsan/kmsan_test.c b/mm/kmsan/kmsan_test.c > index 9733a22c46c1..a062a46b2d24 100644 > --- a/mm/kmsan/kmsan_test.c > +++ b/mm/kmsan/kmsan_test.c > @@ -107,9 +107,9 @@ static bool report_matches(const struct expect_report= *r) > cur =3D expected_header; > end =3D &expected_header[sizeof(expected_header) - 1]; > =20 > - cur +=3D scnprintf(cur, end - cur, "BUG: KMSAN: %s", r->error_type); > + cur =3D seprintf(cur, end, "BUG: KMSAN: %s", r->error_type); > =20 > - scnprintf(cur, end - cur, " in %s", r->symbol); > + seprintf(cur, end, " in %s", r->symbol); > /* The exact offset won't match, remove it; also strip module name. */ > cur =3D strchr(expected_header, '+'); > if (cur) > diff --git a/mm/mempolicy.c b/mm/mempolicy.c > index b28a1e6ae096..c696e4a6f4c2 100644 > --- a/mm/mempolicy.c > +++ b/mm/mempolicy.c > @@ -3359,6 +3359,7 @@ int mpol_parse_str(char *str, struct mempolicy **mp= ol) > void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) > { > char *p =3D buffer; > + char *e =3D buffer + maxlen; > nodemask_t nodes =3D NODE_MASK_NONE; > unsigned short mode =3D MPOL_DEFAULT; > unsigned short flags =3D 0; > @@ -3384,33 +3385,32 @@ void mpol_to_str(char *buffer, int maxlen, struct= mempolicy *pol) > break; > default: > WARN_ON_ONCE(1); > - snprintf(p, maxlen, "unknown"); > + seprintf(p, e, "unknown"); > return; > } > =20 > - p +=3D snprintf(p, maxlen, "%s", policy_modes[mode]); > + p =3D seprintf(p, e, "%s", policy_modes[mode]); > =20 > if (flags & MPOL_MODE_FLAGS) { > - p +=3D snprintf(p, buffer + maxlen - p, "=3D"); > + p =3D seprintf(p, e, "=3D"); > =20 > /* > * Static and relative are mutually exclusive. > */ > if (flags & MPOL_F_STATIC_NODES) > - p +=3D snprintf(p, buffer + maxlen - p, "static"); > + p =3D seprintf(p, e, "static"); > else if (flags & MPOL_F_RELATIVE_NODES) > - p +=3D snprintf(p, buffer + maxlen - p, "relative"); > + p =3D seprintf(p, e, "relative"); > =20 > if (flags & MPOL_F_NUMA_BALANCING) { > if (!is_power_of_2(flags & MPOL_MODE_FLAGS)) > - p +=3D snprintf(p, buffer + maxlen - p, "|"); > - p +=3D snprintf(p, buffer + maxlen - p, "balancing"); > + p =3D seprintf(p, e, "|"); > + p =3D seprintf(p, e, "balancing"); > } > } > =20 > if (!nodes_empty(nodes)) > - p +=3D scnprintf(p, buffer + maxlen - p, ":%*pbl", > - nodemask_pr_args(&nodes)); > + seprintf(p, e, ":%*pbl", nodemask_pr_args(&nodes)); > } > =20 > #ifdef CONFIG_SYSFS > diff --git a/mm/page_owner.c b/mm/page_owner.c > index cc4a6916eec6..5811738e3320 100644 > --- a/mm/page_owner.c > +++ b/mm/page_owner.c > @@ -496,7 +496,7 @@ void pagetypeinfo_showmixedcount_print(struct seq_fil= e *m, > /* > * Looking for memcg information and print it out > */ > -static inline int print_page_owner_memcg(char *kbuf, size_t count, int r= et, > +static inline char *print_page_owner_memcg(char *p, const char end[0], > struct page *page) > { > #ifdef CONFIG_MEMCG > @@ -511,8 +511,7 @@ static inline int print_page_owner_memcg(char *kbuf, = size_t count, int ret, > goto out_unlock; > =20 > if (memcg_data & MEMCG_DATA_OBJEXTS) > - ret +=3D scnprintf(kbuf + ret, count - ret, > - "Slab cache page\n"); > + p =3D seprintf(p, end, "Slab cache page\n"); > =20 > memcg =3D page_memcg_check(page); > if (!memcg) > @@ -520,7 +519,7 @@ static inline int print_page_owner_memcg(char *kbuf, = size_t count, int ret, > =20 > online =3D (memcg->css.flags & CSS_ONLINE); > cgroup_name(memcg->css.cgroup, name, sizeof(name)); > - ret +=3D scnprintf(kbuf + ret, count - ret, > + p =3D seprintf(p, end, > "Charged %sto %smemcg %s\n", > PageMemcgKmem(page) ? "(via objcg) " : "", > online ? "" : "offline ", > @@ -529,7 +528,7 @@ static inline int print_page_owner_memcg(char *kbuf, = size_t count, int ret, > rcu_read_unlock(); > #endif /* CONFIG_MEMCG */ > =20 > - return ret; > + return p; > } > =20 > static ssize_t > @@ -538,14 +537,16 @@ print_page_owner(char __user *buf, size_t count, un= signed long pfn, > depot_stack_handle_t handle) > { > int ret, pageblock_mt, page_mt; > - char *kbuf; > + char *kbuf, *p, *e; > =20 > count =3D min_t(size_t, count, PAGE_SIZE); > kbuf =3D kmalloc(count, GFP_KERNEL); > if (!kbuf) > return -ENOMEM; > =20 > - ret =3D scnprintf(kbuf, count, > + p =3D kbuf; > + e =3D kbuf + count; > + p =3D seprintf(p, e, > "Page allocated via order %u, mask %#x(%pGg), pid %d, tgid %d (%s), t= s %llu ns\n", > page_owner->order, page_owner->gfp_mask, > &page_owner->gfp_mask, page_owner->pid, > @@ -555,7 +556,7 @@ print_page_owner(char __user *buf, size_t count, unsi= gned long pfn, > /* Print information relevant to grouping pages by mobility */ > pageblock_mt =3D get_pageblock_migratetype(page); > page_mt =3D gfp_migratetype(page_owner->gfp_mask); > - ret +=3D scnprintf(kbuf + ret, count - ret, > + p =3D seprintf(p, e, > "PFN 0x%lx type %s Block %lu type %s Flags %pGp\n", > pfn, > migratetype_names[page_mt], > @@ -563,22 +564,23 @@ print_page_owner(char __user *buf, size_t count, un= signed long pfn, > migratetype_names[pageblock_mt], > &page->flags); > =20 > - ret +=3D stack_depot_snprint(handle, kbuf + ret, count - ret, 0); > - if (ret >=3D count) > - goto err; > + p =3D stack_depot_seprint(handle, p, e, 0); > + if (p =3D=3D NULL) > + goto err; // XXX: Should we remove this error handling? > =20 > if (page_owner->last_migrate_reason !=3D -1) { > - ret +=3D scnprintf(kbuf + ret, count - ret, > + p =3D seprintf(p, e, > "Page has been migrated, last migrate reason: %s\n", > migrate_reason_names[page_owner->last_migrate_reason]); > } > =20 > - ret =3D print_page_owner_memcg(kbuf, count, ret, page); > + p =3D print_page_owner_memcg(p, e, page); > =20 > - ret +=3D snprintf(kbuf + ret, count - ret, "\n"); > - if (ret >=3D count) > + p =3D seprintf(p, e, "\n"); > + if (p =3D=3D NULL) > goto err; > =20 > + ret =3D p - kbuf; > if (copy_to_user(buf, kbuf, ret)) > ret =3D -EFAULT; > =20 > diff --git a/mm/slub.c b/mm/slub.c > index be8b09e09d30..b67c6ca0d0f7 100644 > --- a/mm/slub.c > +++ b/mm/slub.c > @@ -7451,6 +7451,7 @@ static char *create_unique_id(struct kmem_cache *s) > { > char *name =3D kmalloc(ID_STR_LENGTH, GFP_KERNEL); > char *p =3D name; > + char *e =3D name + ID_STR_LENGTH; > =20 > if (!name) > return ERR_PTR(-ENOMEM); > @@ -7475,9 +7476,9 @@ static char *create_unique_id(struct kmem_cache *s) > *p++ =3D 'A'; > if (p !=3D name + 1) > *p++ =3D '-'; > - p +=3D snprintf(p, ID_STR_LENGTH - (p - name), "%07u", s->size); > + p =3D seprintf(p, e, "%07u", s->size); > =20 > - if (WARN_ON(p > name + ID_STR_LENGTH - 1)) { > + if (WARN_ON(p =3D=3D NULL)) { > kfree(name); > return ERR_PTR(-EINVAL); > } > --=20 > 2.50.0 >=20 --=20 --sxjq76zh675ubdos Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmhpnv4ACgkQ64mZXMKQ wqk1vg//Vt8t78GPcqFyDdPOtmuNVG3IaCmYiHr+QhI76XyxWTBZJE8MIGoYCrsa 07kxIfpn3/0xcVWyFKMlxoayS+0UcwNaeCNlL1QEbfh4nr860TrqSktol0u65gVF kkzXqZmas40EA8LKrrpragR2XHS96iO8TCuwL6IT2fCKnivMp+a1q3o1DPdQ0tnt fYBLP8Cjr8DLTeExyVy7+9wpNMvvv8//bi+voTQo0ohkMb3+WlxgRxnFWcEy+Z+7 /wTAzXx0lgBOBpz1fF4h4vDNOVgcaW7712ytUeFkm2q6phr3wAVkt1nSf9dY5H8p gIFDblBPekrGY+qe24EUGgETmoyjajmHgsLQu8IfMfg4LBfMQ6bjeH8/Ttvovw0A QlzXS+dTjXw1bFsY1J6IwjczQS5XYodzAbc9zdCTqwB88CUVZcUYhcS7Ed9+W2kN egwZlh4L5+yVNTk9WvwJn4pqFFBcLtJpVtDCngc6eMovbVsid5QqDVJbCJ4cA0EQ NiBsaa7cl53zsVAfzdiIXo7JWmeEjdfvqC5KlW2szEzG2g80Q1jCXLToJcV2/i0K 2XGNCNOoaWAKQh5vxe8y16TSYPOxP+pxz0Sbo7vTZaw7GgwOza285nTN8pMjUbDQ qYT0dagmewcqtlPaXlol0ybzsfK+5tybzJRKnaXXSjDa8/pLIm0= =krbL -----END PGP SIGNATURE----- --sxjq76zh675ubdos--