The buffer is allocated on both devices and OpenCL provides a guranteee that the memory between the two devices is consistent. For example, given a context that has two assocated devices, with command queues cmd1 and cmd2, respectively, then the following is valid:
cl_int in_data = 0x20;
cl_int out_data = 0x0;
cl_event event1, event2;
cl_mem buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(cl_int), NULL, NULL);
clEnqueueWrite(cmd1, buffer, CL_FALSE, 0, sizeof(cl_int), &in_data, 0, NULL, &event1);
clEnqueueRead(cmd2, buffer, CL_FALSE, 0, size(cl_int), &out_data, 1, &event1, &event2);
At this point the expression (out_data == in_data) will evaluate to true. The key point to note is that we preformed a write on cmd1 and a read on cmd2. More detail on why this works can be found in Appendix A of the 1.0 specification.