#define MAX(a, b) ((a) > (b) ? (a) : (b))
This is important because it doesn't cast either arg to any particular type. You can use it with `float`s, or `int`s, or `u_int`s... or a combination. ...
for (i = 0; i < nsyscalls; i++)
npins = MAX(npins, syscalls[i].sysno);
...
`npins` is an `int`, but `sysno` is a `u_int`. C integer promotion rules means that we'll actually be implicitly casting `npins` to a `u_int` here; it's as if we did this: ...
npins = MAX((u_int)npins, syscalls[i].sysno);
...
This means that `npins` can end up as any value we like -- even up to `0xffffffff`. But remember that `npins` is _actually_ a signed int, so once it comes out of `MAX`, it'll be signed again. Thus we can use this to make `npins` negative. ...
npins = MAX(npins, SYS_kbind);
...
Where `SYS_kbind` is just: ...
#define SYS_kbind 86
...
Integer literals in C are signed, so now this use of `MAX` is actually dealing with two signed integers. If we used the loop to make `npins` negative (as described just before) then this line will now take 86 as the maximum of the two values. struct pinsyscall entries[] = {
{ .sysno = 1, .offset = 0x1234 },
{ .sysno = 2, .offset = 0x5678 },
{ .sysno = 1, .offset = 0x9abc }
};
Now `nsyscalls` will be 3 and `pin` will be an array of 3 ints, initialised to `{ 0, 0, 0 }`. 1. `pin[syscalls[0].sysno] = 0x1234` => `pin[1] = 0x1234`
2. `pin[syscalls[1].sysno] = 0x5678` => `pin[2] = 0x5678`
Now when we come to 3, we'll find `pin[syscalls[2].sysno] != 0` since `syscalls[2].sysno == syscalls[0].sysno` - so we set `pin[1] = -1` instead of `0x9abc`. struct pinsyscall entries[] = {
{ .sysno = 0x1111, .offset = 0xdeadbeef }, /* first oob write */
{ .sysno = 0x2222, .offset = 0xf000f000 }, /* second oob write */
{ .sysno = 0xffffffff } /* sets npins to 0xffffffff so we under-allocate */
};
`npins` would be `0xffffffff` after the loop and then the `MAX` at [6] would then return `86`, since `MAX(-1, 86) == 86`. int
elf_read_pintable(struct proc *p, Elf_Phdr *pp, struct vnode *vp,
Elf_Ehdr *eh, uint **pinp)
{
struct pinsyscalls {
u_int offset;
u_int sysno;
} *syscalls = NULL;
int i, npins = 0, nsyscalls;
uint *pins = NULL;
[1] nsyscalls = pp->p_filesz / sizeof(*syscalls);
if (pp->p_filesz != nsyscalls * sizeof(*syscalls))
goto bad;
[2] syscalls = malloc(pp->p_filesz, M_PINSYSCALL, M_WAITOK);
[3] if (elf_read_from(p, vp, pp->p_offset, syscalls,
pp->p_filesz) != 0) {
goto bad;
}
[4] for (i = 0; i < nsyscalls; i++)
[5] npins = MAX(npins, syscalls[i].sysno);
[6] npins = MAX(npins, SYS_kbind); /* XXX see ld.so/loader.c */
[7] npins++;
[8] pins = mallocarray(npins, sizeof(int), M_PINSYSCALL, M_WAITOK|M_ZERO);
for (i = 0; i < nsyscalls; i++) {
[9] if (pins[syscalls[i].sysno])
[10] pins[syscalls[i].sysno] = -1; /* duplicated */
else
[11] pins[syscalls[i].sysno] = syscalls[i].offset;
}
pins[SYS_kbind] = -1; /* XXX see ld.so/loader.c */
*pinp = pins;
pins = NULL;
bad:
free(syscalls, M_PINSYSCALL, nsyscalls * sizeof(*syscalls));
free(pins, M_PINSYSCALL, npins * sizeof(uint));
return npins;
}
So first of all we calculate the number of syscalls in the pin section [1], allocate some memory for it [2] and read it in [3].