Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 440a6cc6 authored by Tobin C. Harding's avatar Tobin C. Harding Committed by Alistair Strachan
Browse files

BACKPORT: vsprintf: refactor %pK code out of pointer()



Currently code to handle %pK is all within the switch statement in
pointer(). This is the wrong level of abstraction. Each of the other switch
clauses call a helper function, pK should do the same.

Refactor code out of pointer() to new function restricted_pointer().

Signed-off-by: default avatarTobin C. Harding <me@tobin.cc>
(cherry picked from commit 57e734423adda83f3b05505875343284efe3b39c)
Signed-off-by: default avatarSandeep Patil <sspatil@android.com>

Bug: 78533979
Test: Build and boot cuttlefish
Change-Id: Ib08350851ab0e99a3569c2c2e12aa421fb6bc622
parent b4d4c265
Loading
Loading
Loading
Loading
+54 −43
Original line number Diff line number Diff line
@@ -1342,6 +1342,59 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
	return string(buf, end, uuid, spec);
}

int kptr_restrict __read_mostly;

static noinline_for_stack
char *restricted_pointer(char *buf, char *end, const void *ptr,
			 struct printf_spec spec)
{
	spec.base = 16;
	spec.flags |= SMALL;
	if (spec.field_width == -1) {
		spec.field_width = 2 * sizeof(ptr);
		spec.flags |= ZEROPAD;
	}

	switch (kptr_restrict) {
	case 0:
		/* Always print %pK values */
		break;
	case 1: {
		const struct cred *cred;

		/*
		 * kptr_restrict==1 cannot be used in IRQ context
		 * because its test for CAP_SYSLOG would be meaningless.
		 */
		if (in_irq() || in_serving_softirq() || in_nmi())
			return string(buf, end, "pK-error", spec);

		/*
		 * Only print the real pointer value if the current
		 * process 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.
		 */
		cred = current_cred();
		if (!has_capability_noaudit(current, CAP_SYSLOG) ||
		    !uid_eq(cred->euid, cred->uid) ||
		    !gid_eq(cred->egid, cred->gid))
			ptr = NULL;
		break;
	}
	case 2:
	default:
		/* Always print 0's for %pK */
		ptr = NULL;
		break;
	}

	return number(buf, end, (unsigned long)ptr, spec);
}

static noinline_for_stack
char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt)
{
@@ -1467,8 +1520,6 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
	return format_flags(buf, end, flags, names);
}

int kptr_restrict __read_mostly;

/*
 * Show a '%p' thing.  A kernel extension is that the '%p' is followed
 * by an extra set of alphanumeric characters that are extended format
@@ -1655,47 +1706,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
			return buf;
		}
	case 'K':
		switch (kptr_restrict) {
		case 0:
			/* Always print %pK values */
			break;
		case 1: {
			const struct cred *cred;

			/*
			 * kptr_restrict==1 cannot be used in IRQ context
			 * because its test for CAP_SYSLOG would be meaningless.
			 */
			if (in_irq() || in_serving_softirq() || in_nmi()) {
				if (spec.field_width == -1)
					spec.field_width = default_width;
				return string(buf, end, "pK-error", spec);
			}

			/*
			 * Only print the real pointer value if the current
			 * process 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.
			 */
			cred = current_cred();
			if (!has_capability_noaudit(current, CAP_SYSLOG) ||
			    !uid_eq(cred->euid, cred->uid) ||
			    !gid_eq(cred->egid, cred->gid))
				ptr = NULL;
			break;
		}
		case 2:
		default:
			/* Always print 0's for %pK */
			ptr = NULL;
			break;
		}
		break;

		return restricted_pointer(buf, end, ptr, spec);
	case 'N':
		return netdev_bits(buf, end, ptr, fmt);
	case 'a':