10/11/2018 Operations in C Have the data, what now? Bit-wise boolean operations Logical operations Operations and Arithmetic Arithmetic operations – 2 – In C Boolean Algebra Algebraic representation of logic Operators the same (&, | , ~, ^) Encode “True” as 1 and “False” as 0 Apply to any “integral” data type long, int, short, char Operators & | ~ ^ View arguments as bit vectors Arguments applied bit-wise AND (&) OR (|) Examples A&B = 1 when both A=1 and B=1 A|B = 1 when either A=1 or B=1 01101001 01101001 01101001 & 01010101 | 01010101 ^ 01010101 ~ 01010101 01000001 01111101 00111100 10101010 01000001 01111101 00111100 10101010 NOT (~) XOR/EXCLUSIVE-OR (^) ~A = 1 when A=0 A^B = 1 when either A=1 or B=1, but not both – 3 – – 4 – 1
10/11/2018 Practice problem Practice problem 0x69 & 0x55 0x69 ^ 0x55 0x69 & 0x55 0x69 ^ 0x55 01101001 01101001 01010101 01010101 01000001 = 0x41 00111100 = 0x3C 0x69 | 0x55 ~0x55 0x69 | 0x55 ~0x55 01101001 01010101 01010101 10101010 = 0xAA 01111101 = 0x7D – 5 – – 6 – Shift Operations Practice problem Left Shift: x << y Argument x 01100010 Shift bit-vector x left y positions x x<<3 x>>2 x>>2 x << 3 00010 000 00010 000 00010 000 Throw away extra bits on left (Logical) (Arithmetic) Fill with 0’s on right Right Shift: x >> y 0xf0 0x80 0x3c 0xfc Shift bit-vector x right y positions Throw away extra bits on right Argument x 10100010 0x0f 0x78 0x03 0x03 Logical shift Log. x >> 2 00 101000 00 101000 00 101000 Fill with 0’s on left Arith. x >>2 11 101000 11 101000 11 101000 Arithmetic shift 0x60 0x33 0xf3 0xcc Replicate most significant bit on left 0xa8 0x15 0x15 Recall two’s complement integer 0x55 representation Perform division by 2 via shift – 7 – – 8 – 2
10/11/2018 Logic Operations in C Logical vs. Bitwise operations Operations always return 0 or 1 Watch out Logical operators versus bitwise boolean operators Comparison operators && versus & > >= < <= == != || versus | Logical Operators == versus = && || ! Logical AND, Logical OR, Logical negation In C (and most languages), 0 is “False”, anything nonzero is “True” Examples (char data type) !0x41 --> 0x00 !0x00 --> 0x01 !!0x41 --> 0x01 What are the values of: 0x69 || 0x55 0x69 | 0x55 What does this expression do? (p && *p) https://freedom-to-tinker.com/blog/felten/the-linux-backdoor-attempt-of-2003/ – 9 – – 10 – Using Bitwise and Logical operations Arithmetic operations Two integers x and y Signed/unsigned Addition and subtraction For any processor, independent of the size of an integer, write C expressions without any “=“ signs that are true if: Multiplication x and y have any non-zero bits in common in their low order byte Division 0xff & (x & y) x has any 1 bits at higher positions than the low order 8 bits ~0xff & x (x & 0xff)^x (x >> 8) x is zero !x x == y !(x^y) – 11 – – 12 – 3
10/11/2018 Unsigned addition Unsigned addition Suppose we have a computer with 4-bit words With 32 bits, unsigned addition is modulo 2 32 What is the unsigned value of 7 + 7? What is the value of 0xc0000000 + 0x70004444 ? 0111 + 0111 = 1110 (14) #include <stdio.h> What about 9 + 9? unsigned int sum(unsigned int a, unsigned int b) { 1001 + 1001 = 0010 (2 or 18 % 2 4 ), % == modulo return a+b; } With w bits, unsigned addition is regular addition, main () { modulo 2 w unsigned int i=0xc0000000; unsigned int j=0x70004444; Bits beyond w are discarded printf("%x\n",sum(i,j)); } Output: 30004444 – 13 – – 14 – Two’s-Complement Addition Two’s-Complement Addition Two’s-complement numbers have a range of Since we are dealing with signed numbers, we can have negative overflow or positive overflow -2 w-1 x, y 2 w-1 -1 w+1 bit result range w-bit result Their sum has the range 2 w-1 x + y x + y – 2 w -2 w-1 x + y < 2 w-1 x + y x + y = t -2 w x + y 2 w -2 w x + y < -2 w-1 x + y + 2 w Both signed and unsigned addition use the same adder x + y 2 w Bit representation for signed and unsigned addition is the Case 4 Positive overflow same x + y t 2 w-1 2 w-1 Case 3 But, truncation of result for signed addition is not modular as in unsigned addition 0 0 Case 2 -2 w-1 -2 w-1 Case 1 Negative overflow -2 w – 15 – – 16 – 4
10/11/2018 Example (w=4) Pointer arithmetic t x y x + y x + y 4 Always unsigned Case 1 -8 -5 -13 3 Based on size of the type being pointed to [1000] [1011] [10011] [0011] Incrementing an (int *) adds 4 to pointer Incrementing a (char *) adds 1 to pointer -8 -8 -16 0 Case 1 [1000] [1000] [10000] [0000] -8 5 -3 -3 Case 2 [1000] [0101] [1101] [1101] Case 3 2 5 7 7 [0010] [0101] [0111] [0111] 5 5 10 -6 Case 4 [0101] [0101] [1010] [1010] 2 w-1 x + y (Case 4) x + y – 2 w , -2 w-1 x + y < 2 w-1 x + y = x + y, (Case 2/3) x + y + 2 w , x + y < -2 w-1 (Case 1) – 17 – – 18 – Pointer addition exercise Unsigned Multiplication Consider the following declaration on For unsigned numbers: 0 x, y 2 w-1 -1 char* cp=0x100; int* ip=0x200; Thus, x and y are w-bit numbers float* fp=0x300; double* dp=0x400; The product x*y: 0 x * y (2 w-1 -1) 2 int i=0x500; Thus, product can require 2w bits What are the hexadecimal values of each after execution of these commands? Only the low w bits are used C Data Typical cp++; 0x101 x86-64 0x204 Type 32-bit The high order bits may overflow ip++; 0x304 fp++; char 1 1 This makes unsigned multiplication modular dp++; 0x408 short 2 2 i++; 0x501 int 4 4 x * y = (x * y) mod 2 w u long w 4 8 float 4 4 double 8 8 pointer 4 8 – 19 – – 20 – 5
10/11/2018 Two’s-Complement Multiplication Security issues with multiplication Same problem as unsigned SUN XDR library Widely used library for transferring data between machines The bit-level representation for two’s-complement and unsigned is identical void* copy_elements(void *ele_src[], int ele_cnt, size_t ele_size); This simplifies the integer multiplier ele_src As before, the interpretation of this value is based on signed vs. unsigned Maintaining exact results Need to keep expanding word size with each product computed Must be done in software, if needed malloc(ele_cnt * ele_size) e.g., by “arbitrary precision” arithmetic packages – 21 – – 22 – XDR Code XDR Vulnerability malloc(ele_cnt * ele_size) void* copy_elements(void *ele_src[], int ele_cnt, size_t ele_size) { /* * Allocate buffer for ele_cnt objects, each of ele_size bytes What if: * and copy from locations designated by ele_src */ = 2 20 + 1 ele_cnt void *result = malloc(ele_cnt * ele_size); if (result == NULL) ele_size = 4096 = 2 12 /* malloc failed */ Allocation = 2 32 + 4096 return NULL; void *next = result; Not checked for overflow int i; Can malloc 4096 when 2 32 +4096 needed for (i = 0; i < ele_cnt; i++) { /* Copy object i to destination */ How can this function be made secure? memcpy(next, ele_src[i], ele_size); Input parameter validation /* Move pointer to next memory region */ next += ele_size; Add assertions (Power of Ten rules) } Use product in for loop after check return result; } – 23 – – 24 – 6
Recommend
More recommend