staticbool bpf_verifier_log_attr_valid(conststruct bpf_verifier_log *log)
{ /* ubuf and len_total should both be specified (or not) together */ if (!!log->ubuf != !!log->len_total) returnfalse; /* log buf without log_level is meaningless */ if (log->ubuf && log->level == 0) returnfalse; if (log->level & ~BPF_LOG_MASK) returnfalse; if (log->len_total > UINT_MAX >> 2) returnfalse; returntrue;
}
/* log attributes have to be sane */ if (!bpf_verifier_log_attr_valid(log)) return -EINVAL;
return0;
}
staticvoid bpf_vlog_update_len_max(struct bpf_verifier_log *log, u32 add_len)
{ /* add_len includes terminal \0, so no need for +1. */
u64 len = log->end_pos + add_len;
/* log->len_max could be larger than our current len due to *bpf_vlog_reset()calls,sowemaintainthemaxofanylengthatany *previouspoint
*/ if (len > UINT_MAX)
log->len_max = UINT_MAX; elseif (len > log->len_max)
log->len_max = len;
}
n += 1; /* include terminating zero */
bpf_vlog_update_len_max(log, n);
if (log->level & BPF_LOG_FIXED) { /* check if we have at least something to put into user buf */
new_n = 0; if (log->end_pos < log->len_total) {
new_n = min_t(u32, log->len_total - log->end_pos, n);
log->kbuf[new_n - 1] = '\0';
}
new_n = min(n, log->len_total);
cur_pos = new_end - new_n;
div_u64_rem(cur_pos, log->len_total, &buf_start);
div_u64_rem(new_end, log->len_total, &buf_end); /* new_end and buf_end are exclusive indices, so if buf_end is *exactlyzero,thenitactuallypointsrighttotheendof *ubufandthereisnowraparound
*/ if (buf_end == 0)
buf_end = log->len_total;
/* if buf_start > buf_end, we wrapped around; *ifbuf_start==buf_end,thenwefillubufcompletely;we *can'thavebuf_start==buf_endtomeanthatthereis *nothingtowrite,becausewealwayswriteatleast *something,evenifterminal'\0'
*/ if (buf_start < buf_end) { /* message fits within contiguous chunk of ubuf */ if (copy_to_user(log->ubuf + buf_start,
log->kbuf + n - new_n,
buf_end - buf_start)) goto fail;
} else { /* message wraps around the end of ubuf, copy in two chunks */ if (copy_to_user(log->ubuf + buf_start,
log->kbuf + n - new_n,
log->len_total - buf_start)) goto fail; if (copy_to_user(log->ubuf,
log->kbuf + n - buf_end,
buf_end)) goto fail;
}
}
if (!bpf_verifier_log_needed(log) || log->level == BPF_LOG_KERNEL) return;
/* if position to which we reset is beyond current log window, *thenwedidn'tpreserveanyusefulcontentandshouldadjust *start_postoendupwithanemptylog(start_pos==end_pos)
*/
log->end_pos = new_pos; if (log->end_pos < log->start_pos)
log->start_pos = log->end_pos;
staticvoid bpf_vlog_reverse_kbuf(char *buf, int len)
{ int i, j;
for (i = 0, j = len - 1; i < j; i++, j--)
swap(buf[i], buf[j]);
}
staticint bpf_vlog_reverse_ubuf(struct bpf_verifier_log *log, int start, int end)
{ /* we split log->kbuf into two equal parts for both ends of array */ int n = sizeof(log->kbuf) / 2, nn; char *lbuf = log->kbuf, *rbuf = log->kbuf + n;
/* Read ubuf's section [start, end) two chunks at a time, from left *andrightside;withineachchunk,swapallthebytes;afterthat *reversetheorderoflbufandrbufandwriteresultbacktoubuf. *Thiswaywe'llendupwithswappedcontentsofspecified *[start,end)ubufsegment.
*/ while (end - start > 1) {
nn = min(n, (end - start ) / 2);
if (copy_from_user(lbuf, log->ubuf + start, nn)) return -EFAULT; if (copy_from_user(rbuf, log->ubuf + end - nn, nn)) return -EFAULT;
/* we write lbuf to the right end of ubuf, while rbuf to the *leftonetoendupwithproperlyreversedoverallubuf
*/ if (copy_to_user(log->ubuf + start, rbuf, nn)) return -EFAULT; if (copy_to_user(log->ubuf + end - nn, lbuf, nn)) return -EFAULT;
start += nn;
end -= nn;
}
return0;
}
int bpf_vlog_finalize(struct bpf_verifier_log *log, u32 *log_size_actual)
{
u32 sublen; int err;
if (!log->ubuf) goto skip_log_rotate; /* If we never truncated log, there is nothing to move around. */ if (log->start_pos == 0) goto skip_log_rotate;
/* Otherwise we need to rotate log contents to make it start from the *bufferbeginningandbeacontinuouszero-terminatedstring.Note *thatiflog->start_pos!=0thenwedefinitelyfilledupentirelog *bufferwithnogaps,andwejustneedtoshiftbuffercontentsto *theleftby(log->start_pos%log->len_total)bytes. * *Unfortunately,userbuffercouldbehugeandwedon'twantto *allocatetemporarykernelmemoryofthesamesizejusttoshift *contentsinastraightforwardfashion.Instead,we'llbecleverand *doin-placearrayrotation.Thisisaleetcode-styleproblem,which *couldbesolvedbythreerotations. * *Let'ssaywehavelogbufferthathastobeshiftedleftby7bytes *(spacesandverticalbarisjustfordemonstrativepurposes): *EFGHIJK|ABCD * *First,wereverseentirearray: *DCBA|KJIHGFE * *Thenwerotatefirst4bytes(DCBA)andseparatelylast7bytes *(KJIHGFE),resultinginaproperlyrotatedarray: *ABCD|EFGHIJK * *We'llutilizelog->kbuftoreadusermemorychunkbychunk,swap *bytes,andwritethemback.Doingitbyte-by-bytewouldbe *unnecessarilyinefficient.Altogetherwearegoingtoreadand *writeeachbytetwice,fortotal4memorycopiesbetweenkerneland *userspace.
*/
/* length of the chopped off part that will be the beginning; *len(ABCD)intheexampleabove
*/
div_u64_rem(log->start_pos, log->len_total, &sublen);
sublen = log->len_total - sublen;
/* properly initialized log has either both ubuf!=NULL and len_total>0 *orubuf==NULLandlen_total==0,soifthisconditiondoesn'thold, *wegotafaultsomewherealongtheway,soreportitback
*/ if (!!log->ubuf != !!log->len_total) return -EFAULT;
/* did truncation actually happen? */ if (log->ubuf && log->len_max > log->len_total) return -ENOSPC;
if (!nr_linfo || insn_off >= prog->len) return NULL;
linfo = prog->aux->linfo; /* Loop invariant: linfo[l].insn_off <= insns_off. *linfo[0].insn_off==0whichalwayssatisfiesabovecondition. *Binarysearchissearchingforrightmostlinfoentrythatsatisfies *theaboveinvariant,givingusthedesiredrecordthatcoversgiven *instructionoffset.
*/
l = 0;
r = nr_linfo - 1; while (l < r) { /* (r - l + 1) / 2 means we break a tie to the right, so if: *l=1,r=2,linfo[l].insn_off<=insn_off,linfo[r].insn_off>insn_off, *thenm=2,weseethatlinfo[m].insn_off>insn_off,andso *rbecomes1andweexittheloopwithcorrectl==1. *Ifthetiewasbrokentotheleft,m=1wouldendusupin *anendlessloopwherelandmstayat1andrstaysat2.
*/
m = l + (r - l + 1) / 2; if (linfo[m].insn_off <= insn_off)
l = m; else
r = m - 1;
}
return &linfo[l];
}
staticconstchar *ltrim(constchar *s)
{ while (isspace(*s))
s++;
/* It often happens that two separate linfo records point to the same *sourcecodeline,buthavedifferingcolumnnumbers.Givenverifier *logdoesn'temitcolumninformation,fromuserperspectivewejust *endupemittingthesamesourcecodelinetwiceunnecessarily. *Soinsteadcheckthatpreviousandcurrentlinforecordpointto *thesamefile(file_name_offsmatch)andthesamelinenumber,and *avoidemittingduplicatedsourcecodelineinsuchcase.
*/ if (prev_linfo && linfo->file_name_off == prev_linfo->file_name_off &&
BPF_LINE_INFO_LINE_NUM(linfo->line_col) == BPF_LINE_INFO_LINE_NUM(prev_linfo->line_col)) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.