diff --git a/src/header/sys_utsname/mod.rs b/src/header/sys_utsname/mod.rs
index 9e74d6f181fb56d229773d67a1f2e661687a9f36..032998d58634fd6e238cd24ce916696557b6164b 100644
--- a/src/header/sys_utsname/mod.rs
+++ b/src/header/sys_utsname/mod.rs
@@ -1,5 +1,6 @@
-//! sys/utsname implementation for linux, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html
+//! sys/utsname implementation, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html
 
+use platform::{Pal, Sys};
 use platform::types::*;
 
 pub const UTSLENGTH: usize = 65;
@@ -14,15 +15,7 @@ pub struct utsname {
     pub domainname: [c_char; UTSLENGTH],
 }
 
-#[cfg(target_os = "linux")]
-mod inner {
-    use super::*;
-    use platform::Sys;
-
-    #[no_mangle]
-    pub unsafe extern "C" fn uname(uts: *mut utsname) -> c_int {
-        Sys::uname(uts)
-    }
+#[no_mangle]
+pub unsafe extern "C" fn uname(uts: *mut utsname) -> c_int {
+    Sys::uname(uts)
 }
-#[cfg(target_os = "linux")]
-pub use self::inner::*;
diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs
index 721c96de21fa9e173041a81165fa59b1133e2064..ce1443c5ceef0af2cb50b85ee193175b8f89b4ce 100644
--- a/src/platform/linux/mod.rs
+++ b/src/platform/linux/mod.rs
@@ -60,10 +60,6 @@ impl Sys {
     // fn times(out: *mut tms) -> clock_t {
     //     unsafe { syscall!(TIMES, out) as clock_t }
     // }
-
-    pub fn uname(utsname: *mut utsname) -> c_int {
-        e(unsafe { syscall!(UNAME, utsname, 0) }) as c_int
-    }
 }
 
 impl Pal for Sys {
@@ -386,6 +382,10 @@ impl Pal for Sys {
         unsafe { syscall!(UMASK, mask) as mode_t }
     }
 
+    fn uname(utsname: *mut utsname) -> c_int {
+        e(unsafe { syscall!(UNAME, utsname, 0) }) as c_int
+    }
+
     fn unlink(path: &CStr) -> c_int {
         e(unsafe { syscall!(UNLINKAT, AT_FDCWD, path.as_ptr(), 0) }) as c_int
     }
diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs
index 14f579cc116b066237c50fa162435ed2e19c8c0a..0866f1f4f3921b76ec741354e025f201b9d40932 100644
--- a/src/platform/pal/mod.rs
+++ b/src/platform/pal/mod.rs
@@ -4,6 +4,7 @@ use header::dirent::dirent;
 use header::sys_select::fd_set;
 use header::sys_stat::stat;
 use header::sys_time::{timeval, timezone};
+use header::sys_utsname::utsname;
 use header::termios::termios;
 use header::time::timespec;
 
@@ -139,6 +140,8 @@ pub trait Pal {
 
     fn umask(mask: mode_t) -> mode_t;
 
+    fn uname(utsname: *mut utsname) -> c_int;
+
     fn unlink(path: &CStr) -> c_int;
 
     fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t;
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index d53cbeb12469adc4b4927b52f7af60bba5ee61c4..df33302644f3e1ca55896a3938151ee0bab986ad 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -3,6 +3,7 @@
 use alloc::collections::BTreeMap;
 use cbitset::BitSet;
 use core::{mem, ptr, slice};
+use core::result::Result as CoreResult;
 use spin::{Mutex, MutexGuard, Once};
 use syscall::data::Stat as redox_stat;
 use syscall::data::TimeSpec as redox_timespec;
@@ -20,6 +21,7 @@ const MAP_ANON: c_int = 1;
 use header::sys_select::fd_set;
 use header::sys_stat::stat;
 use header::sys_time::{timeval, timezone};
+use header::sys_utsname::{utsname, UTSLENGTH};
 use header::termios::termios;
 use header::time::timespec;
 use header::unistd::{F_OK, R_OK, SEEK_SET, W_OK, X_OK};
@@ -903,6 +905,61 @@ impl Pal for Sys {
         e(syscall::umask(mask as usize)) as mode_t
     }
 
+    fn uname(utsname: *mut utsname) -> c_int {
+        fn inner(utsname: *mut utsname) -> CoreResult<(), i32> {
+            let file_path = unsafe { CStr::from_bytes_with_nul_unchecked(b"sys:uname\0") };
+            let mut file = match File::open(file_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
+                Ok(file) => file,
+                Err(_) => return Err(EIO),
+            };
+            let mut lines = BufReader::new(&mut file).lines();
+
+            let mut read_line = |dst: &mut [c_char]| {
+                let line = match lines.next() {
+                    Some(Ok(l)) => {
+                        match CString::new(l) {
+                            Ok(l) => l,
+                            Err(_) => return Err(EIO),
+                        }
+                    },
+                    None | Some(Err(_)) => return Err(EIO),
+                };
+
+                let line_slice: &[c_char] = unsafe {
+                    mem::transmute(line.as_bytes_with_nul())
+                };
+
+                if line_slice.len() <= UTSLENGTH {
+                    dst[..line_slice.len()].copy_from_slice(line_slice);
+                    Ok(())
+                } else {
+                    Err(EIO)
+                }
+            };
+
+            unsafe {
+                read_line(&mut (*utsname).sysname)?;
+                read_line(&mut (*utsname).nodename)?;
+                read_line(&mut (*utsname).release)?;
+                read_line(&mut (*utsname).version)?;
+                read_line(&mut (*utsname).machine)?;
+
+                // Redox doesn't provide domainname in sys:uname
+                //read_line(&mut (*utsname).domainname)?;
+                ptr::write_bytes((*utsname).domainname.as_mut_ptr(), 0, UTSLENGTH);
+            }
+            Ok(())
+        }
+
+        match inner(utsname) {
+            Ok(()) => 0,
+            Err(err) => unsafe {
+                errno = err;
+                -1
+            }
+        }
+    }
+
     fn unlink(path: &CStr) -> c_int {
         e(syscall::unlink(path.to_bytes())) as c_int
     }
diff --git a/tests/Makefile b/tests/Makefile
index 2a8cb5aefce53abd421bb08c786a9750218fd420..e8e4684da49853a94a1b9800a0cd0ed5a34ae325 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -91,6 +91,7 @@ BINS=\
 	stdlib/bsearch \
 	stdlib/mktemp \
 	stdlib/realpath \
+	sys_utsname/uname \
 	time/gettimeofday \
 	unistd/chdir \
 	unistd/getcwd \
diff --git a/tests/sys_utsname/uname.c b/tests/sys_utsname/uname.c
new file mode 100644
index 0000000000000000000000000000000000000000..c58c8cb1922b5b138116db27af1846ae6fc96a1f
--- /dev/null
+++ b/tests/sys_utsname/uname.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <sys/utsname.h>
+
+int main() {
+    struct utsname system_info;
+
+    int result = uname(&system_info);
+
+    if (result < 0) {
+        perror("uname");
+    } else {
+        printf("sysname: '%s'\n", system_info.sysname);
+        printf("nodename: '%s'\n", system_info.nodename);
+        printf("release: '%s'\n", system_info.release);
+        printf("version: '%s'\n", system_info.version);
+        printf("machine: '%s'\n", system_info.machine);
+        printf("domainname: '%s'\n", system_info.domainname);
+    }
+}