CAFEBABE

@CAFEBABE

Software Engineer.

1,972 words

Guestbook
You'll only receive email when CAFEBABE publishes a new post

Books: Notes From PowerSexSuicide By Nick Lane

Mitochondria and Egg Cells: Why (mostly) uniparental inheritence?

  • The Mitochondria in a cell is almost always, but not always, inherited from the mother to eliminate the cytoplasmic competition between two different cytoplasmic components (from different gametes).
    • Mitochondrial DNA gets recombined, when needed, with the damaged genes getting replaced with copies from other chromosomes.
    • Yeasts, Rats, and Bats can recombine mitchondrial DNA
    • There's a recorded case of a human having heart cells containing mitochondria from the father.
  • In a fertilized egg, the mitochondria from the male is either eliminated or selectively silenced, almost always.
  • The zygote (the fertilized egg cell) contains 100,000 mitochondria 99.99% coming from the mother.
  • The zygote divides a number of times within first two weeks to form the embryo: every time the zygote divides the 100,000 mitochondria are distributed among the new cells.
  • Until mitochondria themselves start dividing (asexual reproduction), no new mitochondria are formed during this (first two weeks') period, and the new embryo cells must utilise whatever mitochondria are available to them for their development: any embryo cells that cannot do this die.
  • If the embryo is a female embryo, the egg cells start forming after two/three weeks, and contain around 10 mitochondria, each containing just a single copy of the chromosomes: there's variation in the mitochondrial sequences within these oocytes, and more than 50% contain errors in the DNA sequence.
    • The mitochondrial DNA is verified for a match against the nuclear DNA
  • The number of egg cells formed in a female embryo is around 100 after the first three weeks --> seven million after five months --> two million after birth --> 300,000 by menstruation --> 25,000 by age 40: only 200 of which ovulate during female's reproductive life.


Mitochondria and Ageing: Anti-oxidants do not increase lifespan

  • Denham Harman proposed relation between free-radicals and ageing in 1972: theorized that higher metabolism rate leads to higher free-radicals which cause higher cell damage leading to cell death and, consequently, ageing.
  • Richard Cutler, in 1980's, showed -- erroneously -- that long-lived animals have a higher levels on anti-oxidants in their cells, and conversely, short-lived animals have lower anti-oxidant levels: the data was flawed since he divided the number of anti-oxidants by the metabolic rate in the respective organism, which has the following problems:
    • Opposite is true: a short-lived rat with higher metabolic rate (7 times human metabolic rate) also has a higher anti-oxidant concentration.
    • Several independent studies have confirmed a negative correlation between the antioxidant level and lifespan i.e. the lifespan decreases with the increase in antioxidants: a correlation not causation, since the lifespan is independent of antioxidant concentration.
    • The levels of antioxidant is maintained wrt the metabolic rate: low-for-low/high-for-high to maintain a flexible redox state within the cell.

Java: Serialization

Notes and Format

  • What: Convert an object into a stream of bytes by storing the state of the object.
  • What gets stored in the byte stream:
    • The member variables/fields
    • function signature (but NOT the function's code) impacts the bytes created for the object
  • How: "The default serialization mechanism for an object writes the class of the
    object, the class signature, and the values of all non-transient and
    non-static fields. References to other objects (except in transient or
    static fields) cause those objects to be written also. Multiple references
    to a single object are encoded using a reference sharing mechanism so that
    graphs of objects can be restored to the same shape as when the original was
    written."
  • How: "The default deserialization mechanism for objects restores the contents
    of each field to the value and type it had when it was written. Fields
    declared as transient or static are ignored by the deserialization process.
    References to other objects cause those objects to be read from the stream
    as necessary. Graphs of objects are restored correctly using a reference
    sharing mechanism. New objects are always allocated when deserializing,
    which prevents existing objects from being overwritten."

    "Reading an object is analogous to running the constructors of a new
    object. Memory is allocated for the object and initialized to zero (NULL).
    No-arg constructors are invoked for the non-serializable classes and then
    the fields of the serializable classes are restored from the stream starting
    with the serializable class closest to java.lang.object and finishing with
    the object's most specific class. "  

  • Important: With respect to byte streams, notes on closing the streams:
    • For an output stream, calling close() ensures that the data gets written to its destination (file or whathaveyou); not closing the stream will result in the data being in the buffer without being written to its destination.
    • For an input stream, a file descriptor is associated with the stream, and is stored in the file descriptor table; consequently, the file descriptor table can run out of space if there is a lot of unclosed file streams, and may stop the program from opening new files -- which can be problematic. Close your input file streams.
  • Important: it introduces vulnreability in the code since the serialized byte stream can be easily edited to change bytes such that some invariant of the serialized object is broken.
  • source https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html#10258

Stream Format:

  • Stream Format For Classes

    Magic NumberVersion UIDclassNameserialVersionUIDhandleclassDescFlags bytefield1TypeCode field1NamefieldNTypeCode fieldNName <classNameForFieldOfObjectType>
    fieldBytes
    nullReferenceprevObjectReference

  • Stream Format For Objects        

Magic NumberVersion UIDclassNameserialVersionUIDhandleclassDescFlags bytefield1TypeCode field1NamefieldNTypeCode fieldNName <classNameForFieldOfObjectType>
fieldBytes

nullReference
prevObjectReference
classData[]: fieldsInClass, bytesForPrimitives

stream:
magic version contents



contents:
content contents content



content:
object: classes, outputStream Objects, Enums

blockdata: primitive dataTypes


  • "All of the write methods for primitive types encode their values using a DataOutputStream to put them in the standard stream format. The bytes are buffered into block data records so they can be distinguished from the encoding of objects. This buffering allows primitive data to be skipped if necessary for class versioning. It also allows the stream to be parsed without invoking class-specific methods."


Codes used in the serialized data:

primtypecode:

B = byte

C = char

D = double

F = float

I = integer

J =long

S = short

Z = boolean


objtypecode:

[ = array

L = object


final static short STREAMMAGIC = (short)0xaced;
    final static short STREAMVERSION = 5;
    final static byte TCNULL = (byte)0x70;
    final static byte TCREFERENCE = (byte)0x71;
    final static byte TCCLASSDESC = (byte)0x72;
    final static byte TCOBJECT = (byte)0x73;
    final static byte TCSTRING = (byte)0x74;
    final static byte TCARRAY = (byte)0x75;
    final static byte TCCLASS = (byte)0x76;
    final static byte TCBLOCKDATA = (byte)0x77;
    final static byte TCENDBLOCKDATA = (byte)0x78;
    final static byte TCRESET = (byte)0x79;
    final static byte TCBLOCKDATALONG = (byte)0x7A;
    final static byte TCEXCEPTION = (byte)0x7B;
    final static byte TCLONGSTRING = (byte) 0x7C;
    final static byte TCPROXYCLASSDESC = (byte) 0x7D;
    final static byte TC_ENUM = (byte) 0x7E;
    final static  int   baseWireHandle = 0x7E0000;



Serialization Vulnerability Demonstration Code:
<add after lunch>

Java: Volatile and Synchronized

Gist: a volatile variable isn't enough synchronization.


In Java, a "volatile" field is often presented as a weaker form of synchronization: a field that's specifically indicated to the compiler and runtime as "not-to-be-reordered", which, consequently, doesn't get cached; it is guaranteed to return the most recent write on the field to any threads accessing that field.

Because "most recent write" doesn't always imply "every write", using volatile as a form of synchronization could become problematic.

Consider the code below where the starting balance (represented by volatile member variable balance) is 0; two threads (the main thread, and another created (thread) change the balance to add 100 and 51000 respectively. After execution, one'd expect the final balance to be 51100 (100+51000) for a synchronized operation; however, that isn't what happens: on my machine, the final balance takes values like 51100, 51099, 51000 etc. See the output following the code.

import java.lang.Thread;
/* Over several executions of the program,
 a write to the  volatile variable "balance" 
 either by the main thread or by the created thread 
 is lost i.e. overwritten*/
public class ThreadTest
{
volatile int balance = 0;
public void deposit(int val)
{
balance = balance+val;
}

public void credit(int val)
{
if(balance>0)
balance = balance-val;
}
public void debit(int val) 
{
try
{
Thread internalThread = new Thread(new Runnable(){
@Override
public void run()
{
try
{
System.out.println("pre-change balance in second thread is: "+Integer.toString(balance));

deposit(val);
System.out.println("post-change balance in second thread is: "+Integer.toString(balance));
}
catch(Exception ioe)
{
System.out.println("error in debit thread run.");
}
}
});

internalThread.start();
}
catch(Exception ioe)
{
System.out.println("error in debit().");
}

}
public static void main(String[] args)  throws InterruptedException
{
System.out.println("Main Thread started");
ThreadTest tt = new ThreadTest();


System.out.println("Main Thread starting balance is: "+Integer.toString(tt.balance));

// alter balance from a new thread
tt.debit(100);

// alter balance from the main thread
for(int i = 1;i<=51000; i++)
{
tt.deposit(1);
}

System.out.println("Main Thread changed balance is: "+Integer.toString(tt.balance));
}
}


[my-pc java]$ java ThreadTest  
Main Thread started
Main Thread starting balance is: 0
pre-change balance in second thread is: 1420
post-change balance in second thread is: 2837
Main Thread changed balance is: 51000
[my-pc java]$ java ThreadTest        
Main Thread started
Main Thread starting balance is: 0
pre-change balance in second thread is: 935
post-change balance in second thread is: 1619
Main Thread changed balance is: 51100


In the same code, simply marking the method "deposit()" as synchronized ensures that the final balance is always 51100. Of course, the choice of using a synchronized method or a synchronized block is situational.