Address some security concerns in the cgpt tool.

1. Check for potential integer overflow in sector_bytes * sector_count.
2. Added O_NOFOLLOW to open() call - Is this enough?
3. Passing buffer length to GuidToStr(), PMBRToStr().
4. Use unsigned int in GetEntry() to determine stride.
5. Address conversion between UTF16 and UTF8.

Note: The UTF conversion is complex and troublesome, and needs careful
consideration to get right. For now, I've just forced the interpretation of
the partition name to 7-bit ASCII. That's sufficient for the needs of Chrome
OS, and I can file a new issue to handle UTF correctly.

BUG=chrome-os-partner:705
TEST=manual

Running "make runtests" invokes the tests/run_cgpt_tests.sh script, which checks the behavior and output of the cgpt tool.

Review URL: http://codereview.chromium.org/3594010

Change-Id: I5fd29796d8c929527e0cfbc6d5ccbcdc77502c6b
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
index 1ef74de..9b0805c 100644
--- a/cgpt/cgpt.h
+++ b/cgpt/cgpt.h
@@ -9,6 +9,8 @@
 #define _FILE_OFFSET_BITS 64
 #include <features.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include "endian.h"
 #include "gpt.h"
 #include "cgptlib.h"
@@ -45,7 +47,7 @@
   uint8_t                 sig[2];       // 0x55, 0xaa
 } __attribute__((packed));
 
-void PMBRToStr(struct pmbr *pmbr, char *str);
+void PMBRToStr(struct pmbr *pmbr, char *str, unsigned int buflen);
 
 // Handle to the drive storing the GPT.
 struct drive {
@@ -69,7 +71,7 @@
  */
 #define GUID_STRLEN 37
 int StrToGuid(const char *str, Guid *guid);
-void GuidToStr(const Guid *guid, char *str);
+void GuidToStr(const Guid *guid, char *str, unsigned int buflen);
 int IsZero(const Guid *guid);
 
 
@@ -77,33 +79,33 @@
 int WritePMBR(struct drive *drive);
 
 
-/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
- * Caller must prepare enough space for UTF8. The rough estimation is:
- *
- *   utf8 length = bytecount(utf16) * 1.5
+/* Convert possibly unterminated UTF16 string to UTF8.
+ * Caller must prepare enough space for UTF8, which could be up to
+ * twice the number of UTF16 chars plus the terminating '\0'.
  */
-void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8);
-/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
- * Caller must prepare enough space for UTF16. The conservative estimation is:
- *
- *   utf16 bytecount = bytecount(utf8) / 3 * 4
+void UTF16ToUTF8(const uint16_t *utf16, unsigned int maxinput,
+                 uint8_t *utf8, unsigned int maxoutput);
+/* Convert null-terminated UTF8 string to UTF16.
+ * Caller must prepare enough space for UTF16, including a terminating 0x0000
  */
-void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16);
+void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16, unsigned int maxoutput);
 
 /* Helper functions for supported GPT types. */
 int ResolveType(const Guid *type, char *buf);
 int SupportedType(const char *name, Guid *type);
 void PrintTypes(void);
-void EntryDetails(GptEntry *entry, int index, int raw);
+void EntryDetails(GptEntry *entry, uint32_t index, int raw);
 
 uint32_t GetNumberOfEntries(const GptData *gpt);
-GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index);
-void SetPriority(GptData *gpt, int secondary, int entry_index, int priority);
-int GetPriority(GptData *gpt, int secondary, int entry_index);
-void SetTries(GptData *gpt, int secondary, int entry_index, int tries);
-int GetTries(GptData *gpt, int secondary, int entry_index);
-void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success);
-int GetSuccessful(GptData *gpt, int secondary, int entry_index);
+GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index);
+void SetPriority(GptData *gpt, int secondary, uint32_t entry_index,
+                 int priority);
+int GetPriority(GptData *gpt, int secondary, uint32_t entry_index);
+void SetTries(GptData *gpt, int secondary, uint32_t entry_index, int tries);
+int GetTries(GptData *gpt, int secondary, uint32_t entry_index);
+void SetSuccessful(GptData *gpt, int secondary, uint32_t entry_index,
+                   int success);
+int GetSuccessful(GptData *gpt, int secondary, uint32_t entry_index);
 
 uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers);
 uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries);
@@ -127,5 +129,16 @@
 #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
 const char *GptError(int errnum);
 
+// Size in chars of the GPT Entry's PartitionName field
+#define GPT_PARTNAME_LEN 72
+
+/* The standard "assert" macro goes away when NDEBUG is defined. This doesn't.
+ */
+#define require(A) do { \
+  if (!(A)) { \
+    fprintf(stderr, "condition (%s) failed at %s:%d\n", \
+            #A, __FILE__, __LINE__); \
+    exit(1); } \
+  } while (0)
 
 #endif  // VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_