mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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: Tobin C. Harding <me@tobin.cc>
This commit is contained in:
		
							parent
							
								
									553d8e8b10
								
							
						
					
					
						commit
						57e734423a
					
				
					 1 changed files with 54 additions and 43 deletions
				
			
		| 
						 | 
				
			
			@ -1343,6 +1343,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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1591,8 +1644,6 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
 | 
			
		|||
	return widen_string(buf, buf - buf_start, end, spec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
| 
						 | 
				
			
			@ -1792,47 +1843,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':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue