diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Kconfig.debug | 33 | ||||
| -rw-r--r-- | lib/ashldi3.c | 2 | ||||
| -rw-r--r-- | lib/ashrdi3.c | 2 | ||||
| -rw-r--r-- | lib/asn1_decoder.c | 49 | ||||
| -rw-r--r-- | lib/cmpdi2.c | 2 | ||||
| -rw-r--r-- | lib/kobject_uevent.c | 16 | ||||
| -rw-r--r-- | lib/lshrdi3.c | 2 | ||||
| -rw-r--r-- | lib/mpi/longlong.h | 18 | ||||
| -rw-r--r-- | lib/muldi3.c | 2 | ||||
| -rw-r--r-- | lib/nlattr.c | 22 | ||||
| -rw-r--r-- | lib/oid_registry.c | 16 | ||||
| -rw-r--r-- | lib/rbtree.c | 10 | ||||
| -rw-r--r-- | lib/test_bpf.c | 54 | ||||
| -rw-r--r-- | lib/test_printf.c | 108 | ||||
| -rw-r--r-- | lib/timerqueue.c | 8 | ||||
| -rw-r--r-- | lib/ucmpdi2.c | 2 | ||||
| -rw-r--r-- | lib/vsprintf.c | 194 | 
17 files changed, 370 insertions, 170 deletions
| diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 947d3e2ed5c2..9d5b78aad4c5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1099,8 +1099,6 @@ config PROVE_LOCKING  	select DEBUG_MUTEXES  	select DEBUG_RT_MUTEXES if RT_MUTEXES  	select DEBUG_LOCK_ALLOC -	select LOCKDEP_CROSSRELEASE -	select LOCKDEP_COMPLETIONS  	select TRACE_IRQFLAGS  	default n  	help @@ -1170,37 +1168,6 @@ config LOCK_STAT  	 CONFIG_LOCK_STAT defines "contended" and "acquired" lock events.  	 (CONFIG_LOCKDEP defines "acquire" and "release" events.) -config LOCKDEP_CROSSRELEASE -	bool -	help -	 This makes lockdep work for crosslock which is a lock allowed to -	 be released in a different context from the acquisition context. -	 Normally a lock must be released in the context acquiring the lock. -	 However, relexing this constraint helps synchronization primitives -	 such as page locks or completions can use the lock correctness -	 detector, lockdep. - -config LOCKDEP_COMPLETIONS -	bool -	help -	 A deadlock caused by wait_for_completion() and complete() can be -	 detected by lockdep using crossrelease feature. - -config BOOTPARAM_LOCKDEP_CROSSRELEASE_FULLSTACK -	bool "Enable the boot parameter, crossrelease_fullstack" -	depends on LOCKDEP_CROSSRELEASE -	default n -	help -	 The lockdep "cross-release" feature needs to record stack traces -	 (of calling functions) for all acquisitions, for eventual later -	 use during analysis. By default only a single caller is recorded, -	 because the unwind operation can be very expensive with deeper -	 stack chains. - -	 However a boot parameter, crossrelease_fullstack, was -	 introduced since sometimes deeper traces are required for full -	 analysis. This option turns on the boot parameter. -  config DEBUG_LOCKDEP  	bool "Lock dependency engine debugging"  	depends on DEBUG_KERNEL && LOCKDEP diff --git a/lib/ashldi3.c b/lib/ashldi3.c index 1b6087db95a5..3ffc46e3bb6c 100644 --- a/lib/ashldi3.c +++ b/lib/ashldi3.c @@ -16,7 +16,7 @@  #include <linux/export.h> -#include <lib/libgcc.h> +#include <linux/libgcc.h>  long long notrace __ashldi3(long long u, word_type b)  { diff --git a/lib/ashrdi3.c b/lib/ashrdi3.c index 2e67c97ac65a..ea054550f0e8 100644 --- a/lib/ashrdi3.c +++ b/lib/ashrdi3.c @@ -16,7 +16,7 @@  #include <linux/export.h> -#include <lib/libgcc.h> +#include <linux/libgcc.h>  long long notrace __ashrdi3(long long u, word_type b)  { diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 1ef0cec38d78..dc14beae2c9a 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c @@ -313,42 +313,47 @@ next_op:  	/* Decide how to handle the operation */  	switch (op) { -	case ASN1_OP_MATCH_ANY_ACT: -	case ASN1_OP_MATCH_ANY_ACT_OR_SKIP: -	case ASN1_OP_COND_MATCH_ANY_ACT: -	case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: -		ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); -		if (ret < 0) -			return ret; -		goto skip_data; - -	case ASN1_OP_MATCH_ACT: -	case ASN1_OP_MATCH_ACT_OR_SKIP: -	case ASN1_OP_COND_MATCH_ACT_OR_SKIP: -		ret = actions[machine[pc + 2]](context, hdr, tag, data + dp, len); -		if (ret < 0) -			return ret; -		goto skip_data; -  	case ASN1_OP_MATCH:  	case ASN1_OP_MATCH_OR_SKIP: +	case ASN1_OP_MATCH_ACT: +	case ASN1_OP_MATCH_ACT_OR_SKIP:  	case ASN1_OP_MATCH_ANY:  	case ASN1_OP_MATCH_ANY_OR_SKIP: +	case ASN1_OP_MATCH_ANY_ACT: +	case ASN1_OP_MATCH_ANY_ACT_OR_SKIP:  	case ASN1_OP_COND_MATCH_OR_SKIP: +	case ASN1_OP_COND_MATCH_ACT_OR_SKIP:  	case ASN1_OP_COND_MATCH_ANY:  	case ASN1_OP_COND_MATCH_ANY_OR_SKIP: -	skip_data: +	case ASN1_OP_COND_MATCH_ANY_ACT: +	case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: +  		if (!(flags & FLAG_CONS)) {  			if (flags & FLAG_INDEFINITE_LENGTH) { +				size_t tmp = dp; +  				ret = asn1_find_indefinite_length( -					data, datalen, &dp, &len, &errmsg); +					data, datalen, &tmp, &len, &errmsg);  				if (ret < 0)  					goto error; -			} else { -				dp += len;  			}  			pr_debug("- LEAF: %zu\n", len);  		} + +		if (op & ASN1_OP_MATCH__ACT) { +			unsigned char act; + +			if (op & ASN1_OP_MATCH__ANY) +				act = machine[pc + 1]; +			else +				act = machine[pc + 2]; +			ret = actions[act](context, hdr, tag, data + dp, len); +			if (ret < 0) +				return ret; +		} + +		if (!(flags & FLAG_CONS)) +			dp += len;  		pc += asn1_op_lengths[op];  		goto next_op; @@ -434,6 +439,8 @@ next_op:  			else  				act = machine[pc + 1];  			ret = actions[act](context, hdr, 0, data + tdp, len); +			if (ret < 0) +				return ret;  		}  		pc += asn1_op_lengths[op];  		goto next_op; diff --git a/lib/cmpdi2.c b/lib/cmpdi2.c index 6d7ebf6c2b86..2250da7e503e 100644 --- a/lib/cmpdi2.c +++ b/lib/cmpdi2.c @@ -16,7 +16,7 @@  #include <linux/export.h> -#include <lib/libgcc.h> +#include <linux/libgcc.h>  word_type notrace __cmpdi2(long long a, long long b)  { diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index c3e84edc47c9..2615074d3de5 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -346,7 +346,8 @@ static int kobject_uevent_net_broadcast(struct kobject *kobj,  static void zap_modalias_env(struct kobj_uevent_env *env)  {  	static const char modalias_prefix[] = "MODALIAS="; -	int i; +	size_t len; +	int i, j;  	for (i = 0; i < env->envp_idx;) {  		if (strncmp(env->envp[i], modalias_prefix, @@ -355,11 +356,18 @@ static void zap_modalias_env(struct kobj_uevent_env *env)  			continue;  		} -		if (i != env->envp_idx - 1) -			memmove(&env->envp[i], &env->envp[i + 1], -				sizeof(env->envp[i]) * env->envp_idx - 1); +		len = strlen(env->envp[i]) + 1; + +		if (i != env->envp_idx - 1) { +			memmove(env->envp[i], env->envp[i + 1], +				env->buflen - len); + +			for (j = i; j < env->envp_idx - 1; j++) +				env->envp[j] = env->envp[j + 1] - len; +		}  		env->envp_idx--; +		env->buflen -= len;  	}  } diff --git a/lib/lshrdi3.c b/lib/lshrdi3.c index 8e845f4bb65f..99cfa5721f2d 100644 --- a/lib/lshrdi3.c +++ b/lib/lshrdi3.c @@ -17,7 +17,7 @@   */  #include <linux/module.h> -#include <lib/libgcc.h> +#include <linux/libgcc.h>  long long notrace __lshrdi3(long long u, word_type b)  { diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index 57fd45ab7af1..08c60d10747f 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -671,7 +671,23 @@ do {						\  	**************  MIPS/64  **************  	***************************************/  #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64 -#if (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4) +#if defined(__mips_isa_rev) && __mips_isa_rev >= 6 +/* + * GCC ends up emitting a __multi3 intrinsic call for MIPS64r6 with the plain C + * code below, so we special case MIPS64r6 until the compiler can do better. + */ +#define umul_ppmm(w1, w0, u, v)						\ +do {									\ +	__asm__ ("dmulu %0,%1,%2"					\ +		 : "=d" ((UDItype)(w0))					\ +		 : "d" ((UDItype)(u)),					\ +		   "d" ((UDItype)(v)));					\ +	__asm__ ("dmuhu %0,%1,%2"					\ +		 : "=d" ((UDItype)(w1))					\ +		 : "d" ((UDItype)(u)),					\ +		   "d" ((UDItype)(v)));					\ +} while (0) +#elif (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4)  #define umul_ppmm(w1, w0, u, v) \  do {									\  	typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\ diff --git a/lib/muldi3.c b/lib/muldi3.c index 88938543e10a..54c8b3123376 100644 --- a/lib/muldi3.c +++ b/lib/muldi3.c @@ -15,7 +15,7 @@   */  #include <linux/export.h> -#include <lib/libgcc.h> +#include <linux/libgcc.h>  #define W_TYPE_SIZE 32 diff --git a/lib/nlattr.c b/lib/nlattr.c index 8bf78b4b78f0..dfa55c873c13 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -15,7 +15,11 @@  #include <linux/types.h>  #include <net/netlink.h> -/* for these data types attribute length must be exactly given size */ +/* For these data types, attribute length should be exactly the given + * size. However, to maintain compatibility with broken commands, if the + * attribute length does not match the expected size a warning is emitted + * to the user that the command is sending invalid data and needs to be fixed. + */  static const u8 nla_attr_len[NLA_TYPE_MAX+1] = {  	[NLA_U8]	= sizeof(u8),  	[NLA_U16]	= sizeof(u16), @@ -28,8 +32,16 @@ static const u8 nla_attr_len[NLA_TYPE_MAX+1] = {  };  static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = { +	[NLA_U8]	= sizeof(u8), +	[NLA_U16]	= sizeof(u16), +	[NLA_U32]	= sizeof(u32), +	[NLA_U64]	= sizeof(u64),  	[NLA_MSECS]	= sizeof(u64),  	[NLA_NESTED]	= NLA_HDRLEN, +	[NLA_S8]	= sizeof(s8), +	[NLA_S16]	= sizeof(s16), +	[NLA_S32]	= sizeof(s32), +	[NLA_S64]	= sizeof(s64),  };  static int validate_nla_bitfield32(const struct nlattr *nla, @@ -69,11 +81,9 @@ static int validate_nla(const struct nlattr *nla, int maxtype,  	BUG_ON(pt->type > NLA_TYPE_MAX); -	/* for data types NLA_U* and NLA_S* require exact length */ -	if (nla_attr_len[pt->type]) { -		if (attrlen != nla_attr_len[pt->type]) -			return -ERANGE; -		return 0; +	if (nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) { +		pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n", +				    current->comm, type);  	}  	switch (pt->type) { diff --git a/lib/oid_registry.c b/lib/oid_registry.c index 41b9e50711a7..0bcac6ccb1b2 100644 --- a/lib/oid_registry.c +++ b/lib/oid_registry.c @@ -116,14 +116,14 @@ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)  	int count;  	if (v >= end) -		return -EBADMSG; +		goto bad;  	n = *v++;  	ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40); +	if (count >= bufsize) +		return -ENOBUFS;  	buffer += count;  	bufsize -= count; -	if (bufsize == 0) -		return -ENOBUFS;  	while (v < end) {  		num = 0; @@ -134,20 +134,24 @@ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)  			num = n & 0x7f;  			do {  				if (v >= end) -					return -EBADMSG; +					goto bad;  				n = *v++;  				num <<= 7;  				num |= n & 0x7f;  			} while (n & 0x80);  		}  		ret += count = snprintf(buffer, bufsize, ".%lu", num); -		buffer += count; -		if (bufsize <= count) +		if (count >= bufsize)  			return -ENOBUFS; +		buffer += count;  		bufsize -= count;  	}  	return ret; + +bad: +	snprintf(buffer, bufsize, "(bad)"); +	return -EBADMSG;  }  EXPORT_SYMBOL_GPL(sprint_oid); diff --git a/lib/rbtree.c b/lib/rbtree.c index ba4a9d165f1b..d3ff682fd4b8 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c @@ -603,6 +603,16 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new,  }  EXPORT_SYMBOL(rb_replace_node); +void rb_replace_node_cached(struct rb_node *victim, struct rb_node *new, +			    struct rb_root_cached *root) +{ +	rb_replace_node(victim, new, &root->rb_root); + +	if (root->rb_leftmost == victim) +		root->rb_leftmost = new; +} +EXPORT_SYMBOL(rb_replace_node_cached); +  void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new,  			 struct rb_root *root)  { diff --git a/lib/test_bpf.c b/lib/test_bpf.c index aa8812ae6776..f369889e521d 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -435,6 +435,41 @@ loop:  	return 0;  } +static int bpf_fill_ld_abs_vlan_push_pop2(struct bpf_test *self) +{ +	struct bpf_insn *insn; + +	insn = kmalloc_array(16, sizeof(*insn), GFP_KERNEL); +	if (!insn) +		return -ENOMEM; + +	/* Due to func address being non-const, we need to +	 * assemble this here. +	 */ +	insn[0] = BPF_MOV64_REG(R6, R1); +	insn[1] = BPF_LD_ABS(BPF_B, 0); +	insn[2] = BPF_LD_ABS(BPF_H, 0); +	insn[3] = BPF_LD_ABS(BPF_W, 0); +	insn[4] = BPF_MOV64_REG(R7, R6); +	insn[5] = BPF_MOV64_IMM(R6, 0); +	insn[6] = BPF_MOV64_REG(R1, R7); +	insn[7] = BPF_MOV64_IMM(R2, 1); +	insn[8] = BPF_MOV64_IMM(R3, 2); +	insn[9] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, +			       bpf_skb_vlan_push_proto.func - __bpf_call_base); +	insn[10] = BPF_MOV64_REG(R6, R7); +	insn[11] = BPF_LD_ABS(BPF_B, 0); +	insn[12] = BPF_LD_ABS(BPF_H, 0); +	insn[13] = BPF_LD_ABS(BPF_W, 0); +	insn[14] = BPF_MOV64_IMM(R0, 42); +	insn[15] = BPF_EXIT_INSN(); + +	self->u.ptr.insns = insn; +	self->u.ptr.len = 16; + +	return 0; +} +  static int bpf_fill_jump_around_ld_abs(struct bpf_test *self)  {  	unsigned int len = BPF_MAXINSNS; @@ -6066,6 +6101,14 @@ static struct bpf_test tests[] = {  		{},  		{ {0x1, 0x42 } },  	}, +	{ +		"LD_ABS with helper changing skb data", +		{ }, +		INTERNAL, +		{ 0x34 }, +		{ { ETH_HLEN, 42 } }, +		.fill_helper = bpf_fill_ld_abs_vlan_push_pop2, +	},  };  static struct net_device dev; @@ -6207,9 +6250,8 @@ static struct bpf_prog *generate_filter(int which, int *err)  				return NULL;  			}  		} -		/* We don't expect to fail. */  		if (*err) { -			pr_cont("FAIL to attach err=%d len=%d\n", +			pr_cont("FAIL to prog_create err=%d len=%d\n",  				*err, fprog.len);  			return NULL;  		} @@ -6233,6 +6275,10 @@ static struct bpf_prog *generate_filter(int which, int *err)  		 * checks.  		 */  		fp = bpf_prog_select_runtime(fp, err); +		if (*err) { +			pr_cont("FAIL to select_runtime err=%d\n", *err); +			return NULL; +		}  		break;  	} @@ -6418,8 +6464,8 @@ static __init int test_bpf(void)  				pass_cnt++;  				continue;  			} - -			return err; +			err_cnt++; +			continue;  		}  		pr_cont("jited:%u ", fp->jited); diff --git a/lib/test_printf.c b/lib/test_printf.c index 563f10e6876a..71ebfa43ad05 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -24,24 +24,6 @@  #define PAD_SIZE 16  #define FILL_CHAR '$' -#define PTR1 ((void*)0x01234567) -#define PTR2 ((void*)(long)(int)0xfedcba98) - -#if BITS_PER_LONG == 64 -#define PTR1_ZEROES "000000000" -#define PTR1_SPACES "         " -#define PTR1_STR "1234567" -#define PTR2_STR "fffffffffedcba98" -#define PTR_WIDTH 16 -#else -#define PTR1_ZEROES "0" -#define PTR1_SPACES " " -#define PTR1_STR "1234567" -#define PTR2_STR "fedcba98" -#define PTR_WIDTH 8 -#endif -#define PTR_WIDTH_STR stringify(PTR_WIDTH) -  static unsigned total_tests __initdata;  static unsigned failed_tests __initdata;  static char *test_buffer __initdata; @@ -217,30 +199,79 @@ test_string(void)  	test("a  |   |   ", "%-3.s|%-3.0s|%-3.*s", "a", "b", 0, "c");  } +#define PLAIN_BUF_SIZE 64	/* leave some space so we don't oops */ + +#if BITS_PER_LONG == 64 + +#define PTR_WIDTH 16 +#define PTR ((void *)0xffff0123456789ab) +#define PTR_STR "ffff0123456789ab" +#define ZEROS "00000000"	/* hex 32 zero bits */ + +static int __init +plain_format(void) +{ +	char buf[PLAIN_BUF_SIZE]; +	int nchars; + +	nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); + +	if (nchars != PTR_WIDTH || strncmp(buf, ZEROS, strlen(ZEROS)) != 0) +		return -1; + +	return 0; +} + +#else + +#define PTR_WIDTH 8 +#define PTR ((void *)0x456789ab) +#define PTR_STR "456789ab" + +static int __init +plain_format(void) +{ +	/* Format is implicitly tested for 32 bit machines by plain_hash() */ +	return 0; +} + +#endif	/* BITS_PER_LONG == 64 */ + +static int __init +plain_hash(void) +{ +	char buf[PLAIN_BUF_SIZE]; +	int nchars; + +	nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); + +	if (nchars != PTR_WIDTH || strncmp(buf, PTR_STR, PTR_WIDTH) == 0) +		return -1; + +	return 0; +} + +/* + * We can't use test() to test %p because we don't know what output to expect + * after an address is hashed. + */  static void __init  plain(void)  { -	test(PTR1_ZEROES PTR1_STR " " PTR2_STR, "%p %p", PTR1, PTR2); -	/* -	 * The field width is overloaded for some %p extensions to -	 * pass another piece of information. For plain pointers, the -	 * behaviour is slightly odd: One cannot pass either the 0 -	 * flag nor a precision to %p without gcc complaining, and if -	 * one explicitly gives a field width, the number is no longer -	 * zero-padded. -	 */ -	test("|" PTR1_STR PTR1_SPACES "  |  " PTR1_SPACES PTR1_STR "|", -	     "|%-*p|%*p|", PTR_WIDTH+2, PTR1, PTR_WIDTH+2, PTR1); -	test("|" PTR2_STR "  |  " PTR2_STR "|", -	     "|%-*p|%*p|", PTR_WIDTH+2, PTR2, PTR_WIDTH+2, PTR2); +	int err; -	/* -	 * Unrecognized %p extensions are treated as plain %p, but the -	 * alphanumeric suffix is ignored (that is, does not occur in -	 * the output.) -	 */ -	test("|"PTR1_ZEROES PTR1_STR"|", "|%p0y|", PTR1); -	test("|"PTR2_STR"|", "|%p0y|", PTR2); +	err = plain_hash(); +	if (err) { +		pr_warn("plain 'p' does not appear to be hashed\n"); +		failed_tests++; +		return; +	} + +	err = plain_format(); +	if (err) { +		pr_warn("hashing plain 'p' has unexpected format\n"); +		failed_tests++; +	}  }  static void __init @@ -251,6 +282,7 @@ symbol_ptr(void)  static void __init  kernel_ptr(void)  { +	/* We can't test this without access to kptr_restrict. */  }  static void __init diff --git a/lib/timerqueue.c b/lib/timerqueue.c index 4a720ed4fdaf..0d54bcbc8170 100644 --- a/lib/timerqueue.c +++ b/lib/timerqueue.c @@ -33,8 +33,9 @@   * @head: head of timerqueue   * @node: timer node to be added   * - * Adds the timer node to the timerqueue, sorted by the - * node's expires value. + * Adds the timer node to the timerqueue, sorted by the node's expires + * value. Returns true if the newly added timer is the first expiring timer in + * the queue.   */  bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node)  { @@ -70,7 +71,8 @@ EXPORT_SYMBOL_GPL(timerqueue_add);   * @head: head of timerqueue   * @node: timer node to be removed   * - * Removes the timer node from the timerqueue. + * Removes the timer node from the timerqueue. Returns true if the queue is + * not empty after the remove.   */  bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node)  { diff --git a/lib/ucmpdi2.c b/lib/ucmpdi2.c index 49a53505c8e3..25ca2d4c1e19 100644 --- a/lib/ucmpdi2.c +++ b/lib/ucmpdi2.c @@ -15,7 +15,7 @@   */  #include <linux/module.h> -#include <lib/libgcc.h> +#include <linux/libgcc.h>  word_type __ucmpdi2(unsigned long long a, unsigned long long b)  { diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 1746bae94d41..01c3957b2de6 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -33,6 +33,8 @@  #include <linux/uuid.h>  #include <linux/of.h>  #include <net/addrconf.h> +#include <linux/siphash.h> +#include <linux/compiler.h>  #ifdef CONFIG_BLOCK  #include <linux/blkdev.h>  #endif @@ -1343,6 +1345,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,7 +1646,86 @@ 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; +static noinline_for_stack +char *pointer_string(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; +	} + +	return number(buf, end, (unsigned long int)ptr, spec); +} + +static bool have_filled_random_ptr_key __read_mostly; +static siphash_key_t ptr_key __read_mostly; + +static void fill_random_ptr_key(struct random_ready_callback *unused) +{ +	get_random_bytes(&ptr_key, sizeof(ptr_key)); +	/* +	 * have_filled_random_ptr_key==true is dependent on get_random_bytes(). +	 * ptr_to_id() needs to see have_filled_random_ptr_key==true +	 * after get_random_bytes() returns. +	 */ +	smp_mb(); +	WRITE_ONCE(have_filled_random_ptr_key, true); +} + +static struct random_ready_callback random_ready = { +	.func = fill_random_ptr_key +}; + +static int __init initialize_ptr_random(void) +{ +	int ret = add_random_ready_callback(&random_ready); + +	if (!ret) { +		return 0; +	} else if (ret == -EALREADY) { +		fill_random_ptr_key(&random_ready); +		return 0; +	} + +	return ret; +} +early_initcall(initialize_ptr_random); + +/* Maps a pointer to a 32 bit unique identifier. */ +static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec) +{ +	unsigned long hashval; +	const int default_width = 2 * sizeof(ptr); + +	if (unlikely(!have_filled_random_ptr_key)) { +		spec.field_width = default_width; +		/* string length must be less than default_width */ +		return string(buf, end, "(ptrval)", spec); +	} + +#ifdef CONFIG_64BIT +	hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key); +	/* +	 * Mask off the first 32 bits, this makes explicit that we have +	 * modified the address (and 32 bits is plenty for a unique ID). +	 */ +	hashval = hashval & 0xffffffff; +#else +	hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key); +#endif + +	spec.flags |= SMALL; +	if (spec.field_width == -1) { +		spec.field_width = default_width; +		spec.flags |= ZEROPAD; +	} +	spec.base = 16; + +	return number(buf, end, hashval, spec); +}  /*   * Show a '%p' thing.  A kernel extension is that the '%p' is followed @@ -1698,11 +1832,16 @@ int kptr_restrict __read_mostly;   *                        c major compatible string   *                        C full compatible string   * + * - 'x' For printing the address. Equivalent to "%lx". + *   * ** Please update also Documentation/printk-formats.txt when making changes **   *   * Note: The difference between 'S' and 'F' is that on ia64 and ppc64   * function pointers are really function descriptors, which contain a   * pointer to the real address. + * + * Note: The default behaviour (unadorned %p) is to hash the address, + * rendering it useful as a unique identifier.   */  static noinline_for_stack  char *pointer(const char *fmt, char *buf, char *end, void *ptr, @@ -1792,47 +1931,9 @@ 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; +		if (!kptr_restrict)  			break; -		} -		break; - +		return restricted_pointer(buf, end, ptr, spec);  	case 'N':  		return netdev_bits(buf, end, ptr, fmt);  	case 'a': @@ -1857,15 +1958,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,  		case 'F':  			return device_node_string(buf, end, ptr, spec, fmt + 1);  		} +	case 'x': +		return pointer_string(buf, end, ptr, spec);  	} -	spec.flags |= SMALL; -	if (spec.field_width == -1) { -		spec.field_width = default_width; -		spec.flags |= ZEROPAD; -	} -	spec.base = 16; -	return number(buf, end, (unsigned long) ptr, spec); +	/* default is to _not_ leak addresses, hash before printing */ +	return ptr_to_id(buf, end, ptr, spec);  }  /* |