RDP প্রোটোকলের সাথে কাজ করার জন্য ওপেন সোর্স প্রোগ্রামগুলি পরীক্ষা করার বিষয়ে নিবন্ধগুলির একটি সিরিজের এটি দ্বিতীয় পর্যালোচনা। এতে আমরা rdesktop ক্লায়েন্ট এবং xrdp সার্ভার দেখব।
ত্রুটি শনাক্ত করার জন্য একটি টুল হিসাবে ব্যবহৃত হয়
নিবন্ধটি কেবলমাত্র সেই ত্রুটিগুলি উপস্থাপন করে যা আমার কাছে আকর্ষণীয় বলে মনে হয়েছিল। যাইহোক, প্রকল্পগুলি ছোট, তাই কিছু ভুল ছিল :)।
মন্তব্য. FreeRDP প্রকল্প যাচাইকরণ সম্পর্কে একটি পূর্ববর্তী নিবন্ধ পাওয়া যাবে
rdesktop
এই ক্লায়েন্টটি খুব জনপ্রিয় - এটি ডিফল্টরূপে ReactOS-এ ব্যবহৃত হয় এবং আপনি এটির জন্য তৃতীয়-পক্ষের গ্রাফিকাল ফ্রন্ট-এন্ডগুলিও খুঁজে পেতে পারেন। যাইহোক, তিনি বেশ বয়স্ক: তার প্রথম মুক্তি 4 এপ্রিল, 2001 এ হয়েছিল - লেখার সময়, তার বয়স 17 বছর।
আমি আগে উল্লেখ করেছি, প্রকল্পটি বেশ ছোট। এটিতে প্রায় 30 হাজার লাইন কোড রয়েছে, যা বয়স বিবেচনা করে কিছুটা অদ্ভুত। তুলনা করার জন্য, FreeRDP-এ 320 হাজার লাইন রয়েছে। এখানে ক্লক প্রোগ্রামের আউটপুট রয়েছে:
কোড পাওয়া যাচ্ছে না
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);
}
ত্রুটিটি ফাংশনে অবিলম্বে আমাদের সম্মুখীন হয় প্রধান: আমরা অপারেটরের পরে কোডটি দেখতে পাচ্ছি প্রত্যাবর্তন — এই খণ্ডটি মেমরি পরিষ্কার করে। যাইহোক, ত্রুটিটি কোন হুমকি সৃষ্টি করে না: প্রোগ্রামটি প্রস্থান করার পরে সমস্ত বরাদ্দকৃত মেমরি অপারেটিং সিস্টেম দ্বারা সাফ করা হবে।
কোন ত্রুটি হ্যান্ডলিং
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);
}
....
}
এই ক্ষেত্রে কোড স্নিপেট ফাইলটি শেষ না হওয়া পর্যন্ত ফাইল থেকে একটি বাফারে পড়ে। যাইহোক, এখানে কোন ত্রুটি হ্যান্ডলিং নেই: যদি কিছু ভুল হয়ে যায়, তাহলে পড়া ফিরে আসবে -1, এবং তারপর অ্যারে ওভাররান হবে আউটপুট.
চর প্রকারে EOF ব্যবহার করা
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++;
}
....
}
এখানে আমরা ফাইলের শেষে পৌঁছানোর ভুল হ্যান্ডলিং দেখতে পাচ্ছি: যদি fgetc একটি অক্ষর প্রদান করে যার কোড 0xFF, এটি ফাইলের শেষ হিসাবে ব্যাখ্যা করা হবে (ফাইলের শেষে).
ফাইলের শেষে এটি একটি ধ্রুবক, সাধারণত -1 হিসাবে সংজ্ঞায়িত করা হয়। উদাহরণস্বরূপ, CP1251 এনকোডিং-এ, রাশিয়ান বর্ণমালার শেষ অক্ষরটিতে 0xFF কোড রয়েছে, যা সংখ্যা -1 এর সাথে মিলে যায় যদি আমরা একটি পরিবর্তনশীল সম্পর্কে কথা বলি গৃহস্থালির কাজ. দেখা যাচ্ছে যে প্রতীক 0xFF, মত ফাইলের শেষে (-1) ফাইলের শেষ হিসাবে ব্যাখ্যা করা হয়। এই ধরনের ত্রুটিগুলি এড়াতে, ফাংশনের ফলাফল fgetc একটি পরিবর্তনশীল মত সংরক্ষণ করা উচিত কোন int.
টাইপোস
খণ্ড ঘ
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; // <=
....
}
সম্ভবত এই কোডের লেখক এটি ভুল পেয়েছেন || и && শর্তর মধ্যে. আসুন মানগুলির জন্য সম্ভাব্য বিকল্পগুলি বিবেচনা করি লিখুন_সময় и পরিবর্তন_সময়:
- উভয় ভেরিয়েবল 0 এর সমান: এই ক্ষেত্রে আমরা একটি শাখায় শেষ করব আর: পরিবর্তনশীল mod_time পরবর্তী অবস্থা নির্বিশেষে সর্বদা 0 হবে।
- একটি ভেরিয়েবল হল 0: mod_time 0 এর সমান হবে (অন্য ভেরিয়েবলের একটি নন-নেতিবাচক মান থাকলে), কারণ MIN এর দুটি বিকল্পের মধ্যে ছোটটি বেছে নেবে।
- উভয় ভেরিয়েবল 0 এর সমান নয়: সর্বনিম্ন মান নির্বাচন করুন।
সঙ্গে শর্ত প্রতিস্থাপন যখন লিখুন_সময় এবং পরিবর্তন_সময় আচরণ সঠিক দেখাবে:
- এক বা উভয় ভেরিয়েবল 0 এর সমান নয়: একটি অ-শূন্য মান চয়ন করুন।
- উভয় ভেরিয়েবল 0 এর সমান নয়: সর্বনিম্ন মান নির্বাচন করুন।
খণ্ড ঘ
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;
....
}
দৃশ্যত অপারেটররা এখানেও মিশে গেছে || и &&, বা == и !=: একটি ভেরিয়েবলের মান 20 এবং 9 একই সময়ে থাকতে পারে না।
সীমাহীন লাইন অনুলিপি
RD_NTSTATUS
disk_query_directory(....)
{
....
char *dirname, fullpath[PATH_MAX];
....
/* Get information for directory entry */
sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
....
}
আপনি যখন সম্পূর্ণ ফাংশনটি দেখবেন, তখন এটি পরিষ্কার হয়ে যাবে যে এই কোডটি সমস্যা সৃষ্টি করে না। যাইহোক, তারা ভবিষ্যতে উঠতে পারে: একটি অসতর্ক পরিবর্তন এবং আমরা একটি বাফার ওভারফ্লো পেতে পারি - স্প্রিন্ট কোনো কিছুর দ্বারা সীমাবদ্ধ নয়, তাই পাথগুলিকে সংযুক্ত করার সময় আমরা অ্যারের সীমানার বাইরে যেতে পারি। এই কলটি লক্ষ্য করার পরামর্শ দেওয়া হচ্ছে snprintf(fullpath, PATH_MAX, ....).
অপ্রয়োজনীয় অবস্থা
static void
inRepos(STREAM in, unsigned int read)
{
SERVER_DWORD add = 4 - read % 4;
if (add < 4 && add > 0)
{
....
}
}
পরিদর্শন যোগ করুন > 0 এখানে কোন প্রয়োজন নেই: পরিবর্তনশীল সবসময় শূন্যের চেয়ে বড় হবে, কারণ পড়ুন % 4 ভাগের অবশিষ্টাংশ ফেরত দেবে, কিন্তু এটি কখনই 4 এর সমান হবে না।
xrdp
- xrdp - প্রোটোকল বাস্তবায়ন। Apache 2.0 লাইসেন্সের অধীনে বিতরণ করা হয়েছে।
- xorgxrdp - xrdp-এর সাথে ব্যবহারের জন্য Xorg ড্রাইভারের একটি সেট। লাইসেন্স - X11 (MIT এর মত, কিন্তু বিজ্ঞাপনে ব্যবহার নিষিদ্ধ)
প্রকল্পের উন্নয়ন rdesktop এবং FreeRDP এর ফলাফলের উপর ভিত্তি করে। প্রাথমিকভাবে, গ্রাফিক্সের সাথে কাজ করার জন্য, আপনাকে একটি পৃথক VNC সার্ভার, বা RDP সমর্থন সহ একটি বিশেষ X11 সার্ভার - X11rdp ব্যবহার করতে হয়েছিল, কিন্তু xorgxrdp এর আবির্ভাবের সাথে সাথে তাদের প্রয়োজন অদৃশ্য হয়ে যায়।
এই নিবন্ধে আমরা xorgxrdp কভার করব না।
xrdp প্রকল্প, আগেরটির মতো, খুবই ছোট এবং এতে প্রায় 80 হাজার লাইন রয়েছে।
আরো টাইপো
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++;
}
....
}
....
}
এই কোডটি librfxcodec লাইব্রেরি থেকে নেওয়া হয়েছে, যা RemoteFX এর জন্য jpeg2000 কোডেক প্রয়োগ করে। এখানে, দৃশ্যত, গ্রাফিক ডেটা চ্যানেলগুলি মিশ্রিত করা হয়েছে - "নীল" রঙের পরিবর্তে, "লাল" রেকর্ড করা হয়েছে। এই ত্রুটিটি সম্ভবত কপি-পেস্টের ফলে দেখা দিয়েছে।
একই সমস্যা একটি অনুরূপ ফাংশন ঘটেছে rfx_encode_format_argb, যা বিশ্লেষক আমাদের বলেছেন:
while (x < 64)
{
*la_buf++ = a;
*lr_buf++ = r;
*lg_buf++ = g;
*lb_buf++ = r;
x++;
}
অ্যারে ঘোষণা
// 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];
....
}
....
}
এই দুটি ফাইলে অ্যারের ঘোষণা এবং সংজ্ঞা বেমানান - আকার 1 দ্বারা পৃথক। যাইহোক, কোনও ত্রুটি ঘটে না - সঠিক আকারটি evdev-map.c ফাইলে নির্দিষ্ট করা হয়েছে, তাই সীমার বাইরে নেই। তাই এটি একটি বাগ যা সহজেই ঠিক করা যায়।
ভুল তুলনা
// 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))
{
....
}
....
}
ফাংশন একটি টাইপ পরিবর্তনশীল পড়া স্বাক্ষরযুক্ত স্বল্প মত একটি পরিবর্তনশীল মধ্যে কোন int. এখানে চেক করার প্রয়োজন নেই কারণ আমরা একটি স্বাক্ষরবিহীন ভেরিয়েবল পড়ছি এবং ফলাফলটি একটি বড় ভেরিয়েবলকে বরাদ্দ করছি, তাই ভেরিয়েবলটি নেতিবাচক মান নিতে পারে না।
অপ্রয়োজনীয় চেক
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;
}
....
}
বৈষম্য পরীক্ষা এখানে অর্থপূর্ণ নয় কারণ আমরা ইতিমধ্যেই শুরুতে একটি তুলনা করেছি। সম্ভবত এটি একটি টাইপো এবং বিকাশকারী অপারেটরটি ব্যবহার করতে চেয়েছিলেন৷ || অবৈধ আর্গুমেন্ট ফিল্টার আউট.
উপসংহার
নিরীক্ষা চলাকালীন, কোন গুরুতর ত্রুটি চিহ্নিত করা হয়নি, তবে অনেক ত্রুটি পাওয়া গেছে। যাইহোক, এই ডিজাইনগুলি অনেক সিস্টেমে ব্যবহার করা হয়, যদিও ব্যাপ্তিতে ছোট। একটি ছোট প্রকল্পে অগত্যা অনেক ত্রুটি থাকে না, তাই আপনার বিশ্লেষকের কর্মক্ষমতা শুধুমাত্র ছোট প্রকল্পের উপর বিচার করা উচিত নয়। আপনি নিবন্ধে এই সম্পর্কে আরও পড়তে পারেন "
আপনি আমাদের থেকে PVS-Studio-এর একটি ট্রায়াল সংস্করণ ডাউনলোড করতে পারেন
আপনি যদি এই নিবন্ধটি ইংরেজিভাষী দর্শকদের সাথে ভাগ করতে চান তবে অনুগ্রহ করে অনুবাদ লিঙ্কটি ব্যবহার করুন: সের্গেই লারিন।
উত্স: www.habr.com