Dyma'r ail adolygiad mewn cyfres o erthyglau am brofi rhaglenni ffynhonnell agored ar gyfer gweithio gyda phrotocol y Cynllun Datblygu Gwledig. Ynddo byddwn yn edrych ar y cleient rdesktop a'r gweinydd xrdp.
Fe'i defnyddir fel offeryn i nodi gwallau
Mae'r erthygl yn cyflwyno dim ond y gwallau hynny a oedd yn ymddangos yn ddiddorol i mi. Fodd bynnag, mae'r prosiectau yn fach, felly ychydig o gamgymeriadau oedd :).
Nodyn. Gellir dod o hyd i erthygl flaenorol am ddilysu prosiect FreeRDP
bwrdd gwaith
Mae'r cleient hwn yn boblogaidd iawn - fe'i defnyddir yn ddiofyn yn ReactOS, a gallwch hefyd ddod o hyd i bennau blaen graffigol trydydd parti ar ei gyfer. Fodd bynnag, mae'n eithaf hen: digwyddodd ei ryddhad cyntaf ar Ebrill 4, 2001 - ar adeg ysgrifennu, mae'n 17 oed.
Fel y nodais yn gynharach, mae'r prosiect yn eithaf bach. Mae'n cynnwys tua 30 mil o linellau o god, sy'n rhyfedd braidd o ystyried ei oedran. Er mwyn cymharu, mae FreeRDP yn cynnwys 320 mil o linellau. Dyma allbwn y rhaglen Cloc:
Cod anghyraeddadwy
int
main(int argc, char *argv[])
{
....
return handle_disconnect_reason(deactivated, ext_disc_reason);
if (g_redirect_username)
xfree(g_redirect_username);
xfree(g_username);
}
Mae'r gwall yn dod ar draws ni ar unwaith yn y swyddogaeth prif: gwelwn y cod yn dod ar Γ΄l y gweithredwr dychwelyd β mae'r darn hwn yn glanhau cof. Fodd bynnag, nid yw'r gwall yn fygythiad: bydd yr holl gof a neilltuwyd yn cael ei glirio gan y system weithredu ar Γ΄l i'r rhaglen ddod i ben.
Dim trin gwall
RD_BOOL
subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
{
int n = 1;
char output[256];
....
while (n > 0)
{
n = read(fd[0], output, 255);
output[n] = ' '; // <=
str_handle_lines(output, &rest, linehandler, data);
}
....
}
Mae'r pyt cod yn yr achos hwn yn darllen o'r ffeil i mewn i glustog nes bod y ffeil yn dod i ben. Fodd bynnag, nid oes unrhyw drin gwall yma: os aiff rhywbeth o'i le, yna darllen bydd yn dychwelyd -1, ac yna bydd yr arae yn cael ei or-redeg allbwn.
Defnyddio EOF mewn math torgoch
int
ctrl_send_command(const char *cmd, const char *arg)
{
char result[CTRL_RESULT_SIZE], c, *escaped;
....
while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != 'n')
{
result[index] = c;
index++;
}
....
}
Yma gwelwn drin anghywir o gyrraedd diwedd y ffeil: if fgetc yn dychwelyd nod y mae ei god yn 0xFF, bydd yn cael ei ddehongli fel diwedd y ffeil (EOF).
EOF mae'n gysonyn, a ddiffinnir fel arfer fel -1. Er enghraifft, yn yr amgodio CP1251, mae gan lythyren olaf yr wyddor Rwsieg y cod 0xFF, sy'n cyfateb i'r rhif -1 os ydym yn sΓ΄n am newidyn fel char. Mae'n ymddangos bod y symbol 0xFF, fel EOF (-1) yn cael ei ddehongli fel diwedd y ffeil. Er mwyn osgoi gwallau o'r fath, canlyniad y swyddogaeth yw fgetc dylid ei storio mewn newidyn tebyg int.
Typos
Darn 1
RD_NTSTATUS
disk_set_information(....)
{
time_t write_time, change_time, access_time, mod_time;
....
if (write_time || change_time)
mod_time = MIN(write_time, change_time);
else
mod_time = write_time ? write_time : change_time; // <=
....
}
Efallai bod awdur y cod hwn wedi gwneud camgymeriad || ΠΈ && mewn cyflwr. Gadewch i ni ystyried opsiynau posibl ar gyfer gwerthoedd ysgrifennu_amser ΠΈ newid_amser:
- Mae'r ddau newidyn yn hafal i 0: yn yr achos hwn byddwn yn y pen draw mewn cangen arall: newidyn mod_amser bydd bob amser yn 0 waeth beth fo'r cyflwr dilynol.
- Un o'r newidynnau yw 0: mod_amser yn hafal i 0 (ar yr amod bod gan y newidyn arall werth annegyddol), oherwydd MIN yn dewis y lleiaf o'r ddau opsiwn.
- Nid yw'r ddau newidyn yn hafal i 0: dewiswch y gwerth lleiaf.
Wrth amnewid y cyflwr gyda amser_ysgrifennu && newid_amser bydd yr ymddygiad yn edrych yn gywir:
- Nid yw un neu'r ddau newidyn yn hafal i 0: dewiswch werth nad yw'n sero.
- Nid yw'r ddau newidyn yn hafal i 0: dewiswch y gwerth lleiaf.
Darn 2
static RD_NTSTATUS
disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in,
STREAM out)
{
....
if (((request >> 16) != 20) || ((request >> 16) != 9))
return RD_STATUS_INVALID_PARAMETER;
....
}
Mae'n debyg bod y gweithredwyr yn gymysg yma hefyd || ΠΈ &&Neu == ΠΈ !=: Ni all newidyn gael y gwerth 20 a 9 ar yr un pryd.
CopΓ―o llinell anghyfyngedig
RD_NTSTATUS
disk_query_directory(....)
{
....
char *dirname, fullpath[PATH_MAX];
....
/* Get information for directory entry */
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
....
}
Pan edrychwch ar y swyddogaeth yn llawn, daw'n amlwg nad yw'r cod hwn yn achosi problemau. Fodd bynnag, efallai y byddant yn codi yn y dyfodol: un newid diofal a byddwn yn cael gorlif byffer - gwibio heb ei gyfyngu gan unrhyw beth, felly wrth gydgatenu llwybrau gallwn fynd y tu hwnt i ffiniau'r rhesi. Argymhellir sylwi ar yr alwad hon ymlaen snprintf(llwybr llawn, PATH_MAX, ....).
Cyflwr diangen
static void
inRepos(STREAM in, unsigned int read)
{
SERVER_DWORD add = 4 - read % 4;
if (add < 4 && add > 0)
{
....
}
}
ΠΡΠΎΠ²Π΅ΡΠΊΠ° ychwanegu > 0 nid oes angen yma: bydd y newidyn bob amser yn fwy na sero, oherwydd darllen % 4 yn dychwelyd gweddill y rhaniad, ond ni fydd byth yn hafal i 4.
xrdp
- xrdp - gweithredu protocol. Wedi'i ddosbarthu o dan drwydded Apache 2.0.
- xorgxrdp - Set o yrwyr Xorg i'w defnyddio gyda xrdp. Trwydded - X11 (fel MIT, ond yn gwahardd ei ddefnyddio mewn hysbysebu)
Mae datblygiad y prosiect yn seiliedig ar ganlyniadau rdesktop a FreeRDP. I ddechrau, i weithio gyda graffeg, roedd yn rhaid i chi ddefnyddio gweinydd VNC ar wahΓ’n, neu weinydd X11 arbennig gyda chefnogaeth RDP - X11rdp, ond gyda dyfodiad xorgxrdp, diflannodd yr angen amdanynt.
Yn yr erthygl hon ni fyddwn yn ymdrin Γ’ xorgxrdp.
Mae'r prosiect xrdp, fel yr un blaenorol, yn fach iawn ac yn cynnwys tua 80 mil o linellau.
Mwy o deipos
static int
rfx_encode_format_rgb(const char *rgb_data, int width, int height,
int stride_bytes, int pixel_format,
uint8 *r_buf, uint8 *g_buf, uint8 *b_buf)
{
....
switch (pixel_format)
{
case RFX_FORMAT_BGRA:
....
while (x < 64)
{
*lr_buf++ = r;
*lg_buf++ = g;
*lb_buf++ = r; // <=
x++;
}
....
}
....
}
Cymerwyd y cod hwn o'r llyfrgell librfxcodec, sy'n gweithredu'r codec jpeg2000 ar gyfer RemoteFX. Yma, mae'n debyg, mae'r sianeli data graffig yn gymysg - yn lle'r lliw βglasβ, mae βcochβ yn cael ei gofnodi. Ymddangosodd y gwall hwn yn fwyaf tebygol o ganlyniad i gopΓ―o-gludo.
Digwyddodd yr un broblem mewn swyddogaeth debyg rfx_encode_format_argb, y dywedodd y dadansoddwr wrthym hefyd:
while (x < 64)
{
*la_buf++ = a;
*lr_buf++ = r;
*lg_buf++ = g;
*lb_buf++ = r;
x++;
}
Datganiad Array
// evdev-map.c
int xfree86_to_evdev[137-8+1] = {
....
};
// genkeymap.c
extern int xfree86_to_evdev[137-8];
int main(int argc, char **argv)
{
....
for (i = 8; i <= 137; i++) /* Keycodes */
{
if (is_evdev)
e.keycode = xfree86_to_evdev[i-8];
....
}
....
}
Mae datganiad a diffiniad yr arae yn y ddwy ffeil hyn yn anghydnaws - mae'r maint yn amrywio o 1. Fodd bynnag, nid oes unrhyw wallau - mae'r maint cywir wedi'i nodi yn y ffeil evdev-map.c, felly nid oes unrhyw gyfyngiadau. Felly dim ond nam yw hwn y gellir ei drwsio'n hawdd.
Cymhariaeth anghywir
// common/parse.h
#if defined(B_ENDIAN) || defined(NEED_ALIGN)
#define in_uint16_le(s, v) do
....
#else
#define in_uint16_le(s, v) do
{
(v) = *((unsigned short*)((s)->p));
(s)->p += 2;
} while (0)
#endif
int
xrdp_caps_process_confirm_active(struct xrdp_rdp *self, struct stream *s)
{
int cap_len;
....
in_uint16_le(s, cap_len);
....
if ((cap_len < 0) || (cap_len > 1024 * 1024))
{
....
}
....
}
Mae'r ffwythiant yn darllen newidyn math byr heb ei arwyddo i mewn i newidyn fel int. Nid oes angen gwirio yma oherwydd ein bod yn darllen newidyn heb ei lofnodi ac yn aseinio'r canlyniad i newidyn mwy, felly ni all y newidyn gymryd gwerth negyddol.
Gwiriadau diangen
int EXPORT_CC
libxrdp_send_pointer(struct xrdp_session *session, int cache_idx,
char *data, char *mask, int x, int y, int bpp)
{
....
if ((bpp == 15) && (bpp != 16) && (bpp != 24) && (bpp != 32))
{
g_writeln("libxrdp_send_pointer: error");
return 1;
}
....
}
Nid yw gwiriadau anghydraddoldeb yn gwneud synnwyr yma gan fod gennym gymhariaeth yn barod ar y dechrau. Mae'n debygol mai teipio yw hwn ac roedd y datblygwr eisiau defnyddio'r gweithredwr || i hidlo dadleuon annilys.
Casgliad
Yn ystod yr archwiliad, ni chanfuwyd unrhyw wallau difrifol, ond canfuwyd llawer o ddiffygion. Fodd bynnag, defnyddir y dyluniadau hyn mewn llawer o systemau, er eu bod yn fach o ran cwmpas. Nid oes gan brosiect bach lawer o wallau o reidrwydd, felly ni ddylech farnu perfformiad y dadansoddwr ar brosiectau bach yn unig. Gallwch ddarllen mwy am hyn yn yr erthygl β
Gallwch lawrlwytho fersiwn prawf o PVS-Studio oddi wrthym
Os ydych chi am rannu'r erthygl hon Γ’ chynulleidfa Saesneg ei hiaith, defnyddiwch y ddolen gyfieithu: Sergey Larin.
Ffynhonnell: hab.com