On Wed, 2013-10-09 at 11:15 +1100, Ryan Mallon wrote:
> Some setuid binaries will allow reading of files which have read
> permission by the real user id. This is problematic with files which
> use %pK because the file access permission is checked at open() time,
> but the kptr_restrict setting is checked at read() time. If a setuid
> binary opens a %pK file as an unprivileged user, and then elevates
> permissions before reading the file, then kernel pointer values may be
> leaked.

I think it should explicitly test 0.

Dan? Might this be any problem?

Otherwise, just style notes:

> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
[]
> @@ -1312,10 +1312,26 @@ char *pointer(const char *fmt, char *buf, char *end, 
> void *ptr,
>                               spec.field_width = default_width;
>                       return string(buf, end, "pK-error", spec);
>               }
> -             if (!((kptr_restrict == 0) ||
> -                   (kptr_restrict == 1 &&
> -                    has_capability_noaudit(current, CAP_SYSLOG))))
> -                     ptr = NULL;
> +
> +             /*
> +              * If kptr_restrict is set to 2, then %pK always prints as
> +              * NULL. If it is set to 1, then only print the real pointer
> +              * value if the current proccess has CAP_SYSLOG and is running
> +              * with the same credentials it started with. This is because
> +              * access to files is checked at open() time, but %pK checks
> +              * permission at read() time. We don't want to leak pointer
> +              * values if a binary opens a file using %pK and then elevates
> +              * privileges before reading it.
> +              */
> +             {
> +                     const struct cred *cred = current_cred();

Please add #include <linux/cred.h>

> +                     if (kptr_restrict == 2 || (kptr_restrict == 1 &&
> +                          (!has_capability_noaudit(current, CAP_SYSLOG) ||
> +                           !uid_eq(cred->euid, cred->uid) ||
> +                           !gid_eq(cred->egid, cred->gid))))
> +                             ptr = NULL;
> +             }
>               break;

Also, it might be easier to read as:

                if (kptr_restrict == 0)
                        break;
                else if (kptr_restrict == 1) {
                        const struct cred *cred = current_cred();

                        if (!has_capability_noaudit(current, CAP_SYSLOG) ||
                            !uid_eq(cred->euid, cred->uid) ||
                            !gid_eq(cred->egid, cred->gid))
                                ptr = NULL;
                } else {
                        ptr = NULL;
                }
                break;

>       case 'N':
>               switch (fmt[1]) {


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to