Re: [PATCH 2/2] vfs: Fix inode ownership checks with regard to foreign ownership
Jeffrey Altman <[email protected]> Mon, 21 Jul 2025 12:15:34 -0400
| Newsgroups | gmane.linux.file-systems,gmane.linux.kernel,gmane.comp.file-systems.openafs.devel,gmane.linux.kernel.cifs |
|---|---|
| Message-ID | <[email protected]> |
--Apple-Mail=_E92E1DC6-D9C2-4C3F-BA21-8F84E080A0C3 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On May 29, 2025, at 9:03=E2=80=AFPM, Jeffrey E Altman = <[email protected]> wrote: >=20 > On 5/19/2025 12:11 PM, David Howells wrote: >=20 >> Fix a number of ownership checks made by the VFS that assume that >> inode->i_uid is meaningful with respect to the UID space of the = system >> performing the check. Network filesystems, however, may violate this >> assumption - and, indeed, a network filesystem may not even have an = actual >> concept of a UNIX integer UID (cifs, for example). >>=20 >> There are a number of places within the VFS where UID checks are made = and >> some of these should be deferring the interpretation to the = filesystem by >> way of the previously added vfs_inode_is_owned_by_me() and >> vfs_inodes_have_same_owner(): >>=20 >> (*) chown_ok() >> (*) chgrp_ok() >>=20 >> These should call vfs_inode_is_owned_by_me(). Possibly these = need to >> defer all their checks to the network filesystem as the = interpretation >> of the new UID/GID depends on the netfs too, but the ->setattr() >> method gets a chance to deal with that. >>=20 >> (*) do_coredump() >>=20 >> Should probably call vfs_is_owned_by_me() to check that the file >> created is owned by the caller - but the check that's there = might be >> sufficient. >>=20 >> (*) inode_owner_or_capable() >>=20 >> Should call vfs_is_owned_by_me(). I'm not sure whether the = namespace >> mapping makes sense in such a case, but it probably could be = used. >>=20 >> (*) vfs_setlease() >>=20 >> Should call vfs_is_owned_by_me(). Actually, it should query if >> leasing is permitted. >>=20 >> Also, setting locks could perhaps do with a permission call to = the >> filesystem driver as AFS, for example, has a lock permission bit = in >> the ACL, but since the AFS server checks that when the RPC call = is >> made, it's probably unnecessary. >>=20 >> (*) acl_permission_check() >> (*) posix_acl_permission() >>=20 >> These functions are only used by generic_permission() which is >> overridden if ->permission() is supplied, and when evaluating a = POSIX >> ACL, it should arguably be checking the UID anyway. >>=20 >> AFS, for example, implements its own ACLs and evaluates them in >> ->permission() and on the server. >>=20 >> (*) may_follow_link() >>=20 >> Should call vfs_is_owned_by_me() and also vfs_have_same_owner() = on the >> the link and its parent dir. The latter only applies on >> world-writable sticky dirs. >>=20 >> (*) may_create_in_sticky() >>=20 >> The initial subject of this patch. Should call = vfs_is_owned_by_me() >> and also vfs_have_same_owner() both. >>=20 >> (*) __check_sticky() >>=20 >> Should call vfs_is_owned_by_me() on both the dir and the inode. >>=20 >> (*) may_dedupe_file() >>=20 >> Should call vfs_is_owned_by_me(). >>=20 >> (*) IMA policy ops. >>=20 >> I'm not sure what the best way to deal with this is - if, = indeed, it >> needs any changes. >>=20 >> Note that wrapping stuff up into vfs_inode_is_owned_by_me() isn't >> necessarily the most efficient as it means we may end up doing the = uid >> idmapping an extra time - though mostly this is in places where I'm = not >> sure it matters so much. >>=20 >> Signed-off-by: David Howells <[email protected]> >> cc: Etienne Champetier <[email protected]> >> cc: Marc Dionne <[email protected]> >> cc: Jeffrey Altman <[email protected]> >> cc: Chet Ramey <[email protected]> >> cc: Cheyenne Wills <[email protected]> >> cc: Alexander Viro <[email protected]> >> cc: Christian Brauner <[email protected]> >> cc: Steve French <[email protected]> >> cc: Mimi Zohar <[email protected]> >> cc: [email protected] >> cc: [email protected] >> cc: [email protected] >> cc: [email protected] >> cc: [email protected] >> Link: = https://groups.google.com/g/gnu.bash.bug/c/6PPTfOgFdL4/m/2AQU-S1N76UJ >> Link: = https://git.savannah.gnu.org/cgit/bash.git/tree/redir.c?h=3Dbash-5.3-rc1#n= 733 >> --- >> fs/attr.c | 58 = +++++++++++++++++++++++++++++------------------- >> fs/coredump.c | 3 +-- >> fs/inode.c | 8 +++++-- >> fs/locks.c | 7 ++++-- >> fs/namei.c | 30 +++++++++++++------------ >> fs/remap_range.c | 20 +++++++++-------- >> 6 files changed, 74 insertions(+), 52 deletions(-) >>=20 >> diff --git a/fs/attr.c b/fs/attr.c >> index 9caf63d20d03..fefd92af56a2 100644 >> --- a/fs/attr.c >> +++ b/fs/attr.c >> @@ -16,6 +16,7 @@ >> #include <linux/fcntl.h> >> #include <linux/filelock.h> >> #include <linux/security.h> >> +#include "internal.h" >> /** >> * setattr_should_drop_sgid - determine whether the setgid bit needs = to be >> @@ -91,19 +92,21 @@ EXPORT_SYMBOL(setattr_should_drop_suidgid); >> * permissions. On non-idmapped mounts or if permission checking is = to be >> * performed on the raw inode simply pass @nop_mnt_idmap. >> */ >> -static bool chown_ok(struct mnt_idmap *idmap, >> - const struct inode *inode, vfsuid_t ia_vfsuid) >> +static int chown_ok(struct mnt_idmap *idmap, >> + const struct inode *inode, vfsuid_t ia_vfsuid) >> { >> vfsuid_t vfsuid =3D i_uid_into_vfsuid(idmap, inode); >> - if (vfsuid_eq_kuid(vfsuid, current_fsuid()) && >> - vfsuid_eq(ia_vfsuid, vfsuid)) >> - return true; >> + int ret; >> + >> + ret =3D vfs_inode_is_owned_by_me(idmap, inode); >> + if (ret <=3D 0) >> + return ret; >> if (capable_wrt_inode_uidgid(idmap, inode, CAP_CHOWN)) >> - return true; >> + return 0; >> if (!vfsuid_valid(vfsuid) && >> ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN)) >> - return true; >> - return false; >> + return 0; >> + return -EPERM; >> } >> /** >> @@ -118,23 +121,27 @@ static bool chown_ok(struct mnt_idmap *idmap, >> * permissions. On non-idmapped mounts or if permission checking is = to be >> * performed on the raw inode simply pass @nop_mnt_idmap. >> */ >> -static bool chgrp_ok(struct mnt_idmap *idmap, >> - const struct inode *inode, vfsgid_t ia_vfsgid) >> +static int chgrp_ok(struct mnt_idmap *idmap, >> + const struct inode *inode, vfsgid_t ia_vfsgid) >> { >> vfsgid_t vfsgid =3D i_gid_into_vfsgid(idmap, inode); >> - vfsuid_t vfsuid =3D i_uid_into_vfsuid(idmap, inode); >> - if (vfsuid_eq_kuid(vfsuid, current_fsuid())) { >> + int ret; >> + >> + ret =3D vfs_inode_is_owned_by_me(idmap, inode); >> + if (ret < 0) >> + return ret; >> + if (ret =3D=3D 0) { >> if (vfsgid_eq(ia_vfsgid, vfsgid)) >> - return true; >> + return 0; >> if (vfsgid_in_group_p(ia_vfsgid)) >> - return true; >> + return 0; >> } >> if (capable_wrt_inode_uidgid(idmap, inode, CAP_CHOWN)) >> - return true; >> + return 0; >> if (!vfsgid_valid(vfsgid) && >> ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN)) >> - return true; >> - return false; >> + return 0; >> + return -EPERM; >> } >> /** >> @@ -163,6 +170,7 @@ int setattr_prepare(struct mnt_idmap *idmap, = struct dentry *dentry, >> { >> struct inode *inode =3D d_inode(dentry); >> unsigned int ia_valid =3D attr->ia_valid; >> + int ret; >> /* >> * First check size constraints. These can't be overriden using >> @@ -179,14 +187,18 @@ int setattr_prepare(struct mnt_idmap *idmap, = struct dentry *dentry, >> goto kill_priv; >> /* Make sure a caller can chown. */ >> - if ((ia_valid & ATTR_UID) && >> - !chown_ok(idmap, inode, attr->ia_vfsuid)) >> - return -EPERM; >> + if (ia_valid & ATTR_UID) { >> + ret =3D chown_ok(idmap, inode, attr->ia_vfsuid); >> + if (ret < 0) >> + return ret; >> + } >> /* Make sure caller can chgrp. */ >> - if ((ia_valid & ATTR_GID) && >> - !chgrp_ok(idmap, inode, attr->ia_vfsgid)) >> - return -EPERM; >> + if (ia_valid & ATTR_GID) { >> + ret =3D chgrp_ok(idmap, inode, attr->ia_vfsgid); >> + if (ret < 0) >> + return ret; >> + } >> /* Make sure a caller can chmod. */ >> if (ia_valid & ATTR_MODE) { >> diff --git a/fs/coredump.c b/fs/coredump.c >> index c33c177a701b..ded3936b2067 100644 >> --- a/fs/coredump.c >> +++ b/fs/coredump.c >> @@ -720,8 +720,7 @@ void do_coredump(const kernel_siginfo_t *siginfo) >> * filesystem. >> */ >> idmap =3D file_mnt_idmap(cprm.file); >> - if (!vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode), >> - current_fsuid())) { >> + if (vfs_inode_is_owned_by_me(idmap, inode) !=3D 0) { >> coredump_report_failure("Core dump to %s aborted: " >> "cannot preserve file owner", cn.corename); >> goto close_fail; >> diff --git a/fs/inode.c b/fs/inode.c >> index 99318b157a9a..7e91b6f87757 100644 >> --- a/fs/inode.c >> +++ b/fs/inode.c >> @@ -2586,11 +2586,15 @@ bool inode_owner_or_capable(struct mnt_idmap = *idmap, >> { >> vfsuid_t vfsuid; >> struct user_namespace *ns; >> + int ret; >> - vfsuid =3D i_uid_into_vfsuid(idmap, inode); >> - if (vfsuid_eq_kuid(vfsuid, current_fsuid())) >> + ret =3D vfs_inode_is_owned_by_me(idmap, inode); >> + if (ret =3D=3D 0) >> return true; >> + if (ret < 0) >> + return false; >> + vfsuid =3D i_uid_into_vfsuid(idmap, inode); >> ns =3D current_user_ns(); >> if (vfsuid_has_mapping(ns, vfsuid) && ns_capable(ns, CAP_FOWNER)) >> return true; >> diff --git a/fs/locks.c b/fs/locks.c >> index 1619cddfa7a4..b7a2a3ab7529 100644 >> --- a/fs/locks.c >> +++ b/fs/locks.c >> @@ -68,6 +68,7 @@ >> #include <trace/events/filelock.h> >> #include <linux/uaccess.h> >> +#include "internal.h" >> static struct file_lock *file_lock(struct file_lock_core *flc) >> { >> @@ -2013,10 +2014,12 @@ int >> vfs_setlease(struct file *filp, int arg, struct file_lease **lease, = void **priv) >> { >> struct inode *inode =3D file_inode(filp); >> - vfsuid_t vfsuid =3D i_uid_into_vfsuid(file_mnt_idmap(filp), inode); >> int error; >> - if ((!vfsuid_eq_kuid(vfsuid, current_fsuid())) && = !capable(CAP_LEASE)) >> + error =3D vfs_inode_is_owned_by_me(file_mnt_idmap(filp), inode); >> + if (error < 0) >> + return error; >> + if (error !=3D 0 && !capable(CAP_LEASE)) >> return -EACCES; >> if (!S_ISREG(inode->i_mode)) >> return -EINVAL; >> diff --git a/fs/namei.c b/fs/namei.c >> index 9f42dc46322f..6ede952d424a 100644 >> --- a/fs/namei.c >> +++ b/fs/namei.c >> @@ -1195,26 +1195,26 @@ static int vfs_inodes_have_same_owner(struct = mnt_idmap *idmap, struct inode *ino >> * >> * Returns 0 if following the symlink is allowed, -ve on error. >> */ >> -static inline int may_follow_link(struct nameidata *nd, const struct = inode *inode) >> +static inline int may_follow_link(struct nameidata *nd, struct inode = *inode) >> { >> struct mnt_idmap *idmap; >> - vfsuid_t vfsuid; >> + int ret; >> if (!sysctl_protected_symlinks) >> return 0; >> - idmap =3D mnt_idmap(nd->path.mnt); >> - vfsuid =3D i_uid_into_vfsuid(idmap, inode); >> - /* Allowed if owner and follower match. */ >> - if (vfsuid_eq_kuid(vfsuid, current_fsuid())) >> - return 0; >> - >> /* Allowed if parent directory not sticky and world-writable. */ >> if ((nd->dir_mode & (S_ISVTX|S_IWOTH)) !=3D (S_ISVTX|S_IWOTH)) >> return 0; >> + idmap =3D mnt_idmap(nd->path.mnt); >> + /* Allowed if owner and follower match. */ >> + ret =3D vfs_inode_is_owned_by_me(idmap, inode); >> + if (ret <=3D 0) >> + return ret; >> + >> /* Allowed if parent directory and link owner match. */ >> - if (vfsuid_valid(nd->dir_vfsuid) && vfsuid_eq(nd->dir_vfsuid, = vfsuid)) >> + if (vfs_inodes_have_same_owner(idmap, inode, nd)) >> return 0; >> if (nd->flags & LOOKUP_RCU) >> @@ -3157,12 +3157,14 @@ EXPORT_SYMBOL(user_path_at); >> int __check_sticky(struct mnt_idmap *idmap, struct inode *dir, >> struct inode *inode) >> { >> - kuid_t fsuid =3D current_fsuid(); >> + int ret; >> - if (vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode), fsuid)) >> - return 0; >> - if (vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, dir), fsuid)) >> - return 0; >> + ret =3D vfs_inode_is_owned_by_me(idmap, inode); >> + if (ret <=3D 0) >> + return ret; >> + ret =3D vfs_inode_is_owned_by_me(idmap, dir); >> + if (ret <=3D 0) >> + return ret; >> return !capable_wrt_inode_uidgid(idmap, inode, CAP_FOWNER); >> } >> EXPORT_SYMBOL(__check_sticky); >> diff --git a/fs/remap_range.c b/fs/remap_range.c >> index 26afbbbfb10c..9eee93c27001 100644 >> --- a/fs/remap_range.c >> +++ b/fs/remap_range.c >> @@ -413,20 +413,22 @@ loff_t vfs_clone_file_range(struct file = *file_in, loff_t pos_in, >> EXPORT_SYMBOL(vfs_clone_file_range); >> /* Check whether we are allowed to dedupe the destination file */ >> -static bool may_dedupe_file(struct file *file) >> +static int may_dedupe_file(struct file *file) >> { >> struct mnt_idmap *idmap =3D file_mnt_idmap(file); >> struct inode *inode =3D file_inode(file); >> + int ret; >> if (capable(CAP_SYS_ADMIN)) >> - return true; >> + return 0; >> if (file->f_mode & FMODE_WRITE) >> - return true; >> - if (vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode), = current_fsuid())) >> - return true; >> + return 0; >> + ret =3D vfs_inode_is_owned_by_me(idmap, inode); >> + if (ret <=3D 0) >> + return ret; >> if (!inode_permission(idmap, inode, MAY_WRITE)) >> - return true; >> - return false; >> + return 0; >> + return -EPERM; >> } >> loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t = src_pos, >> @@ -459,8 +461,8 @@ loff_t vfs_dedupe_file_range_one(struct file = *src_file, loff_t src_pos, >> if (ret) >> return ret; >> - ret =3D -EPERM; >> - if (!may_dedupe_file(dst_file)) >> + ret =3D may_dedupe_file(dst_file); >> + if (ret < 0) >> goto out_drop_write; >> ret =3D -EXDEV; >=20 > Reviewed-by: Jeffrey Altman <[email protected]> >=20 > This change looks good to me. It should be noted that it assumes that = filesystem specific is_owned_by_me inode_operation can properly handle = all inode types. The preceding change will need a fix for the afs = implementation. Some further thoughts on this series: 1. Can vfs_inode_is_owned_by_me() be restricted to regular files and = symlinks? AFS cannot provide an answer via the PRSFS_ADMINISTER flag for = directories and with the exception of __check_sticky() it is never = called on a directory inode. 2. __check_sticky() can be changed from calling is_owned_by_me() on both = the file and the directory to using is_owned_by_me() for the file and = then use a have_same_owner() check to compare the file and directory = inodes. Doing so avoids the only vfs_inode_is_owned_by_me() call on a = directory inode. 3. Can we add a new vfs_is chown_ok() inode operation? AFS does not use = vnode ownership as the determining factor when permitting alteration of = the unix owner/group. Only members of the AFS cell=E2=80=99s = system:administrators group are permitted to change ownership and the = client has no visibility into group memberships so must either always = assume its ok to attempt the ownership change and let the fileserver = reject it, or the AFS fileserver needs to implement a new rpc or caller = access bit to determine if the caller is a system:administrator or = otherwise has permission to change object ownership. Thanks. Jeffrey Altman --Apple-Mail=_E92E1DC6-D9C2-4C3F-BA21-8F84E080A0C3 Content-Disposition: attachment; filename=smime.p7s Content-Type: application/pkcs7-signature; name=smime.p7s Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCDHEw ggXSMIIEuqADAgECAhBAAYJpmi/rPn/F0fJyDlzMMA0GCSqGSIb3DQEBCwUAMDoxCzAJBgNVBAYT AlVTMRIwEAYDVQQKEwlJZGVuVHJ1c3QxFzAVBgNVBAMTDlRydXN0SUQgQ0EgQTEzMB4XDTIyMDgw NDE2MDQ0OFoXDTI1MTAzMTE2MDM0OFowcDEvMC0GCgmSJomT8ixkAQETH0EwMTQxMEQwMDAwMDE4 MjY5OUEyRkQyMDAwMjMzQ0QxGTAXBgNVBAMTEEplZmZyZXkgRSBBbHRtYW4xFTATBgNVBAoTDEF1 cmlTdG9yIEluYzELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCk C7PKBBZnQqDKPtZPMLAy77zo2DPvwtGnd1hNjPvbXrpGxUb3xHZRtv179LHKAOcsY2jIctzieMxf 82OMyhpBziMPsFAG/ukihBMFj3/xEeZVso3K27pSAyyNfO/wJ0rX7G+ges22Dd7goZul8rPaTJBI xbZDuaykJMGpNq4PQ8VPcnYZx+6b+nJwJJoJ46kIEEfNh3UKvB/vM0qtxS690iAdgmQIhTl+qfXq 4IxWB6b+3NeQxgR6KLU4P7v88/tvJTpxIKkg9xj89ruzeThyRFd2DSe3vfdnq9+g4qJSHRXyTft6 W3Lkp7UWTM4kMqOcc4VSRdufVKBQNXjGIcnhAgMBAAGjggKcMIICmDAOBgNVHQ8BAf8EBAMCBPAw gYQGCCsGAQUFBwEBBHgwdjAwBggrBgEFBQcwAYYkaHR0cDovL2NvbW1lcmNpYWwub2NzcC5pZGVu dHJ1c3QuY29tMEIGCCsGAQUFBzAChjZodHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL2Nl cnRzL3RydXN0aWRjYWExMy5wN2MwHwYDVR0jBBgwFoAULbfeG1l+KpguzeHUG+PFEBJe6RQwCQYD VR0TBAIwADCCASsGA1UdIASCASIwggEeMIIBGgYLYIZIAYb5LwAGAgEwggEJMEoGCCsGAQUFBwIB Fj5odHRwczovL3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRpZmljYXRlcy9wb2xpY3kvdHMvaW5k ZXguaHRtbDCBugYIKwYBBQUHAgIwga0MgapUaGlzIFRydXN0SUQgQ2VydGlmaWNhdGUgaGFzIGJl ZW4gaXNzdWVkIGluIGFjY29yZGFuY2Ugd2l0aCBJZGVuVHJ1c3QncyBUcnVzdElEIENlcnRpZmlj YXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRpZmlj YXRlcy9wb2xpY3kvdHMvaW5kZXguaHRtbDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vdmFsaWRh dGlvbi5pZGVudHJ1c3QuY29tL2NybC90cnVzdGlkY2FhMTMuY3JsMB8GA1UdEQQYMBaBFGphbHRt YW5AYXVyaXN0b3IuY29tMB0GA1UdDgQWBBQB+nzqgljLocLTsiUn2yWqEc2sgjAdBgNVHSUEFjAU BggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQELBQADggEBAJwVeycprp8Ox1npiTyfwc5Q aVaqtoe8Dcg2JXZc0h4DmYGW2rRLHp8YL43snEV93rPJVk6B2v4cWLeQfaMrnyNeEuvHx/2CT44c dLtaEk5zyqo3GYJYlLcRVz6EcSGHv1qPXgDT0xB/25etwGYqutYF4Chkxu4KzIpq90eDMw5ajkex w+8ARQz4N5+d6NRbmMCovd7wTGi8th/BZvz8hgKUiUJoQle4wDxrdXdnIhCP7g87InXKefWgZBF4 VX21t2+hkc04qrhIJlHrocPG9mRSnnk2WpsY0MXta8ivbVKtfpY7uSNDZSKTDi1izEFH5oeQdYRk gIGb319a7FjslV8wggaXMIIEf6ADAgECAhBAAXA7OrqBjMk8rp4OuNQSMA0GCSqGSIb3DQEBCwUA MEoxCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlJZGVuVHJ1c3QxJzAlBgNVBAMTHklkZW5UcnVzdCBD b21tZXJjaWFsIFJvb3QgQ0EgMTAeFw0yMDAyMTIyMTA3NDlaFw0zMDAyMTIyMTA3NDlaMDoxCzAJ BgNVBAYTAlVTMRIwEAYDVQQKEwlJZGVuVHJ1c3QxFzAVBgNVBAMTDlRydXN0SUQgQ0EgQTEzMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu6sUO01SDD99PM+QdZkNxKxJNt0NgQE+Zt6i xaNP0JKSjTd+SG5LwqxBWjnOgI/3dlwgtSNeN77AgSs+rA4bK4GJ75cUZZANUXRKw/et8pf9Qn6i qgB63OdHxBN/15KbM3HR+PyiHXQoUVIevCKW8nnlWnnZabT1FejOhRRKVUg5HACGOTfnCOONrlxl g+m1Vjgno1uNqNuLM/jkD1z6phNZ/G9IfZGI0ppHX5AA/bViWceX248VmefNhSR14ADZJtlAAWOi 2un03bqrBPHA9nDyXxI8rgWLfUP5rDy8jx2hEItg95+ORF5wfkGUq787HBjspE86CcaduLka/Bk2 VwIDAQABo4IChzCCAoMwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwgYkGCCsG AQUFBwEBBH0wezAwBggrBgEFBQcwAYYkaHR0cDovL2NvbW1lcmNpYWwub2NzcC5pZGVudHJ1c3Qu Y29tMEcGCCsGAQUFBzAChjtodHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL3Jvb3RzL2Nv bW1lcmNpYWxyb290Y2ExLnA3YzAfBgNVHSMEGDAWgBTtRBnA0/AGi+6ke75C5yZUyI42djCCASQG A1UdIASCARswggEXMIIBEwYEVR0gADCCAQkwSgYIKwYBBQUHAgEWPmh0dHBzOi8vc2VjdXJlLmlk ZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5odG1sMIG6BggrBgEFBQcC AjCBrQyBqlRoaXMgVHJ1c3RJRCBDZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQgaW4gYWNjb3Jk YW5jZSB3aXRoIElkZW5UcnVzdCdzIFRydXN0SUQgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0 IGh0dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRl eC5odG1sMEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20v Y3JsL2NvbW1lcmNpYWxyb290Y2ExLmNybDAdBgNVHQ4EFgQULbfeG1l+KpguzeHUG+PFEBJe6RQw HQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4ICAQB/7BKcygLX 6Nl4a03cDHt7TLdPxCzFvDF2bkVYCFTRX47UfeomF1gBPFDee3H/IPlLRmuTPoNt0qjdpfQzmDWN 95jUXLdLPRToNxyaoB5s0hOhcV6H08u3FHACBif55i0DTDzVSaBv0AZ9h1XeuGx4Fih1Vm3Xxz24 GBqqVudvPRLyMJ7u6hvBqTIKJ53uCs3dyQLZT9DXnp+kJv8y7ZSAY+QVrI/dysT8avtn8d7k7azN BkfnbRq+0e88QoBnel6u+fpwbd5NLRHywXeH+phbzULCa+bLPRMqJaW2lbhvSWrMHRDy3/d8Hvgn LCBFK2s4Spns4YCN4xVcbqlGWzgolHCKUH39vpcsDo1ymZFrJ8QR6ihIn8FmJ5oKwAnnd/G6ADXF C9budb9+532phSAXOZrrecIQn+vtP366PC+aClAPsIIDJDsotS5z4X2JUFsNIuEgXGqhiKE7SuZb rFG9sdcLprSlJN7TsRDc0W2b9nqwD+rj/5MN0C+eKwha+8ydv0+qzTyxPP90KRgaegGowC4dUsZy Tk2n4Z3MuAHX5nAZL/Vh/SyDj/ajorV44yqZBzQ3ChKhXbfUSwe2xMmygA2Z5DRwMRJnp/BscizY dNk2WXJMTnH+wVLN8sLEwEtQR4eTLoFmQvrK2AMBS9kW5sBkMzINt/ZbbcZ3F+eAMDGCAqYwggKi AgEBME4wOjELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUlkZW5UcnVzdDEXMBUGA1UEAxMOVHJ1c3RJ RCBDQSBBMTMCEEABgmmaL+s+f8XR8nIOXMwwDQYJYIZIAWUDBAIBBQCgggEpMBgGCSqGSIb3DQEJ AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI1MDcyMTE2MTUzNFowLwYJKoZIhvcNAQkE MSIEIGmh3ewuaJUXoA2nojfFkJ8krl19veC583XhdAZtg68rMF0GCSsGAQQBgjcQBDFQME4wOjEL MAkGA1UEBhMCVVMxEjAQBgNVBAoTCUlkZW5UcnVzdDEXMBUGA1UEAxMOVHJ1c3RJRCBDQSBBMTMC EEABgmmaL+s+f8XR8nIOXMwwXwYLKoZIhvcNAQkQAgsxUKBOMDoxCzAJBgNVBAYTAlVTMRIwEAYD VQQKEwlJZGVuVHJ1c3QxFzAVBgNVBAMTDlRydXN0SUQgQ0EgQTEzAhBAAYJpmi/rPn/F0fJyDlzM MA0GCSqGSIb3DQEBCwUABIIBAIQ6rwUQD84MFvEdiq/vvMCbd/WZpwvCOmqY6ndutTGVkrF8HfMV BVJJJVXbIDIFZcpp315AsQwqX3Tp5m7iqA0E0es9lFT6fs1UGBimcOIt5Aj08pWk3mLcspK0LbSi HJmvwfJWXesgj4Ra4MeoYeprjAXobwzV4G6dTHQY8CigA2NTHDZXbZI+n0KpsGXD5y5+yzKhme+2 IMxlP2DuwQYgjqh3o1flRQmJh0z4DCHUzByK1TUDQNp5yuGXDvVJA2uWAdZRz8piGv+mUFoMViO2 W8FElecUnepNM9CjQlkcEX9jcmjK52SUrs6mqZdTHG4++a6x/snnvBfS14wqbDIAAAAAAAA= --Apple-Mail=_E92E1DC6-D9C2-4C3F-BA21-8F84E080A0C3--