在内核Documentation/sysctl/kernel.txt中对其使用有介绍,如下所示:
kptr_restrict:
This toggle indicates whether restrictions are placed on
exposing kernel addresses via /proc and other interfaces.
When kptr_restrict is set to 0 (the default) the address is hashed before
printing. (This is the equivalent to %p.)
When kptr_restrict is set to (1), kernel pointers printed using the %pK
format specifier will be replaced with 0's unless the user has CAP_SYSLOG
and effective user and group ids are equal to the real ids. This is
because %pK checks are done at read() time rather than open() time, so
if permissions are elevated between the open() and the read() (e.g via
a setuid binary) then %pK will not leak kernel pointers to unprivileged
users. Note, this is a temporary solution only. The correct long-term
solution is to do the permission checks at open() time. Consider removing
world read permissions from files that use %pK, and using dmesg_restrict
to protect against uses of %pK in dmesg(8) if leaking kernel pointer
values to unprivileged users is a concern.
When kptr_restrict is set to (2), kernel pointers printed using
%pK will be replaced with 0's regardless of privileges.
简单来讲,变量kptr_restrict是可以用来限制内核地址的打印,当kptr_restrict=0时,会直接打印内核地址(%p和%pK效果一样);当kptr_restrict=1时,若在中断上下文或软中断时,%pK打印“pK-error”,否则内核地址打印全0;当kptr_restrict=2时,%pK打印内核地址为全0;而内核地址以%p打印时无论在什么情况下都会以HASH地址方式打印,而%pK可以通过 变量kptr_restrict隐藏内核地址,防止内核地址泄漏。
可以通过代码简单看出:
char *restricted_pointer(char *buf, char *end, const void *ptr,
struct printf_spec spec)
{
switch (kptr_restrict) {
case 0:
/* Handle as %p, hash and do _not_ leak addresses. */
return ptr_to_id(buf, end, ptr, spec); //直接打印内核地址HASH值
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 = 2 * sizeof(ptr);
return error_string(buf, end, "pK-error", spec); //在中断上下文或软中断等处,打印“pK-error”
}
/*
* 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; //直接打印全0
break;
}
case 2:
default:
/* Always print 0's for %pK */
ptr = NULL;
break;
}
以下为以%pK打印内核地址:
在未修改时或kptr_restrict=0时,内核地址打印如下所示:
Euler:/home # ./test.sh
disable begin 0
[ 128.153235] hisi_sas_v3_hw 0000:74:02.0: erroneous completion iptt=4030 task=0000000021ed4560 dev id=1 CQ hdr: 0x1103 0x10fbe 0x0
0x20000 Error info: 0x0 0x4000000 0x0 0x0
[ 128.168481] sas: smp_execute_task_sg: task to dev 500e004aaaaaaa1f response: 0x0 status 0x2
[ 128.177189] sas: broadcast received: 0
[ 128.180938] sas: REVALIDATING DOMAIN on port 0, pid:3519
修改kptr_restrict=1时,内核地址打印如下所示:
Euler:/home # ./test.sh
disable begin 0
[ 226.287150] hisi_sas_v3_hw 0000:74:02.0: erroneous completion iptt=4064 task= pK-error dev id=1 CQ hdr: 0x1103 0x10fe0 0x0
0x20000 Error info: 0x0 0x4000000 0x0 0x0
[ 226.302395] sas: smp_execute_task_sg: task to dev 500e004aaaaaaa1f response: 0x0 status 0x2
[ 226.311106] sas: broadcast received: 0
[ 226.314852] sas: REVALIDATING DOMAIN on port 0, pid:3519
修改kptr_restrict=2时,内核地址打印如下所示:
Euler:/home # ./test.sh
disable begin 0
[ 506.507222] hisi_sas_v3_hw 0000:74:02.0: erroneous completion iptt=4041 task=0000000000000000 dev id=1 CQ hdr: 0x1103 0x10fc9 0x0
0x20000 Error info: 0x0 0x4000000 0x0 0x0
[ 506.522471] sas: smp_execute_task_sg: task to dev 500e004aaaaaaa1f response: 0x0 status 0x2
[ 506.531174] sas: broadcast received: 0
[ 506.534918] sas: REVALIDATING DOMAIN on port 0, pid:3519